Custom date data type in C I've created a very basic date data type in C simply to practice writing my own data type. Please critique.

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
enum DATE_FORMAT{DASHES,SLASHES};
typedef enum DATE_FORMAT DFORMAT;
typedef struct {
    unsigned char day;
    unsigned char month;
    unsigned short year;
} DATE;

/* Allocates new DATE with specified values and returns a ptr to it. User must NULL-check */
DATE *create_date(unsigned char month, unsigned char day, unsigned short year)
{
    if((month &gt; 12) || (month &lt; 1))
        return NULL;
    if((day &gt; 31) || (day &lt; 1))
        return NULL;
    if((year &gt; 9999) || (year &lt; 0))
        return NULL;
    DATE *the_date = malloc(sizeof(DATE));
    if(the_date == NULL)
        return NULL;
    the_date-&gt;day = day;
    the_date-&gt;month = month;
    the_date-&gt;year = year;
    return the_date;
}
void printf_date(DATE *input, DFORMAT format)
{
    if(input == NULL)
        printf("Invalid DATE.\n");
    if(format == DASHES)
        printf("%hhu-%hhu-%hu\n",input-&gt;month,input-&gt;day,input-&gt;year);
    if(format == SLASHES)
        printf("%hhu/%hhu/%hu\n",input-&gt;month,input-&gt;day,input-&gt;year);
    return;
}
void free_date(DATE *dtf)
{
    if(dtf == NULL)
    {
        printf("Date free failed.\n");
    }
    else
    {
        free(dtf);
        printf("Date freed successfully\n");
    }
    return;
}


int main()
{
    DATE *my_date = create_date(3,17,2017);
    if(my_date == NULL)
    {
        printf("Please provide a valid date next time... exiting.\n");
        return(EXIT_FAILURE);
    }
    printf_date(my_date, SLASHES);
    printf_date(my_date, DASHES);
    free_date(my_date);
    return(EXIT_SUCCESS);
}
DATE *create_date(unsigned char month, unsigned char day, unsigned short year)



What if I want to create a DATE on the stack?




    if((month &gt; 12) || (month &lt; 1))
        return NULL;
    if((day &gt; 31) || (day &lt; 1))
        return NULL;
    if((year &gt; 9999) || (year &lt; 0))
        return NULL;



There are many date libraries out there, and they're not consistent on their offsets for months. I would consider creating an enum for the months.

Also, either don't validate the values at all or validate them fully. If I can't create 2017-13-01 then why can I create 2017-02-31? If I can't create a date in 753 BC then why can I create a date in year 0 (whatever that means &ndash; 1 BC?)?

Obviously that comes with some caveats, particularly with respect to the transition from the Julian to the Gregorian calendar; the documentation should make it clear what the transition date is and what days don't exist in consequence.




void printf_date(DATE *input, DFORMAT format)



Wouldn't sprintf_date be more useful? You can print to stdout given sprintf, but you can't print to anything other than stdout given only printf.


        printf("%hhu-%hhu-%hu\n",input-&gt;month,input-&gt;day,input-&gt;year);






        printf("%hhu/%hhu/%hu\n",input-&gt;month,input-&gt;day,input-&gt;year);



No. Just no. ISO 8601 is the only date format that should be used unless a locale parameter is supported.