GDateTime

I got fed up with working around all the limitations with date and time in glib and C (time_t, struct timeval, struct tm, GTimeVal, GDate, etc) so I decided to write something new.

The result is GDateTime. It handles dates and times from 1/1/1 to 12/31/9999 on 100-nanosecond intervals. As requested by a few individuals, it is an opaque/boxed type. String parsing is incomplete but the rest should be in good shape.

The glib branch is available here. Or for those with short attention spans, the header gdatetime.h.

You can even use GDateTimes as keys within a GHashTable using g_date_time_hash, g_date_time_equal.

GHashTable *hash = g_hash_table_new_full (g_date_time_hash, g_date_time_equal, g_date_time_free, NULL);

I'm interested in feedback and patches.

Comments (17)

  1. Richard wrote:

    What about when I want to reference 06/06/-6000? :)

    Saturday, October 3, 2009 at 11:55 pm #
  2. cosimoc wrote:

    This seems really cool, thanks for your work.
    I like the .NET DateTime approach to the matter and would like to see something similar merged in GLib proper; at a first glance, you seem to be missing internationalization all around though, is this intentional?

    Sunday, October 4, 2009 at 12:08 am #
  3. chergert wrote:

    @cosimic yeah i’m just not there yet, i would love some suggestions from those who are experienced with it. this also only covers the Gregorian calendar just like .NET’s System.DateTime.

    @Richard yeah, unfortunately I don’t know really of any system that will handle that. certainly not time_t :-) it’s a trade off between infinite extensibility and practical use.

    Sunday, October 4, 2009 at 12:32 am #
  4. Any plans on submitting this to glib?

    Sunday, October 4, 2009 at 1:07 am #
  5. chergert wrote:

    I’ve made it known in the irc channel, hopefully with some good suggestions and comments from the community it will be in an acceptable shape to merge in soon.

    Sunday, October 4, 2009 at 1:16 am #
  6. Benjamin Otte wrote:

    Here’s a bunch of things about the API that came to mind:
    - As said on IRC: better make GTimeSpan typedef to a gint64 and supply macros G_TIME_SPAN_SECOND/MINUTE/DAY and G_TIME_SPAN_TO/FROM_SECONDS/MINUTES/DAYS() – that eases working with the code (adding, subtracting etc) and interop with other libraries.
    - Should GDateTime instances be constant after creation? That way you couldn’t support g_date_time_add_*() and had to use g_date_time_new_*() instead, but would always be sure about the value of a GDateTime. )Plus, I’m a big fan of constant types.)
    - s/g_date_time_humanize/g_date_time_format_for_display/ seems the more glib’y way to say this.
    - Is daylight savings a world wide concept? Or do some weird countries have even more than two different times of the year? Is it even worth supporting in an API? Isn’t DST represented as a different timezone? (I know it is in central europe)
    - The API is very verbose – less functions would probably be better. Do we really need g_date_time_tomorrow() for example?
    - g_date_time_to_timeval() should probably clamp instead of doing nothing when it returns false. This function seems like an excellent case of “oops, forgot to check return value” bugs
    - s/g_date_time_parse_exact/g_date_time_parse_with_format/ or so – otherwise I’ll be wondering if g_date_time_parse() wouldn’t create an exact date.
    - I got you talked with Juerg about utc vs local handling, so I’m not gonna comment on this.

    Sunday, October 4, 2009 at 10:25 am #
  7. Will this me do the following, which I’ve had great difficulty doing in Glom’s code:
    - Allow me to display a date for humans, always with 4-digit years, in the current locale.

    - Interpret that date when the user enters it.

    Standard C and C++ are surprisingly bad at this.

    Also, can this easily handle just a date and just a time?

    Sunday, October 4, 2009 at 11:01 am #
  8. stephane wrote:

    While you’re at it, don’t try to mimic .NET System.DateTime. mimic System.DateTimeOffset instead !

    Sunday, October 4, 2009 at 11:01 am #
  9. chergert wrote:

    @Murray

    g_date_time_humanize() should do this (I’ll rename it per Benjamin’s request). I can add an equal parser as well (parse_from_display).

    g_date_time_date() will return a new datetime that is set to midnight for the day. alternatively, _today(), _yesterday(), _tomorrow(), work just as well. that should suffice for days without locking you into a separate date-only type.

    As for times, i think the similar should be fine (just keep the default 1/1/1 date).

    Sunday, October 4, 2009 at 11:16 am #
  10. gantenbein wrote:

    The best Date/Time API out there that I know of is Joda Time:

    http://joda-time.sourceforge.net/

    DateTime class:
    http://joda-time.sourceforge.net/api-release/org/joda/time/DateTime.html

    However, it uses fluent interfaces which is fine for languages with object oriented syntax, but would be less intuitive for C.

    Sunday, October 4, 2009 at 11:25 am #
  11. gnudoc wrote:

    Thanks for this. I can barely read C, so there’s no way I can meaningfully contribute to the code, but you mentioned only using the gregorian calendar in your comment there.

    If the implication was that you’d be interested in adding support for non-gregorian calendars then I can possibly help there – although probably not with actual patches. I’m very familiar with the hijri calendar, which is the one used in arab and other islamic countries (wrote a perl script to convert between them a long time ago), so if you were interested in suppporting it please let me know.

    Sunday, October 4, 2009 at 5:47 pm #
  12. chergert wrote:

    For those following this let me give a short update.

    Most of Benjamin’s suggestions have been implemented.

    • Clamp result of g_date_time_to_time_t() and g_date_time_to_timeval() to nearest representable value when outside of range.
    • Remove g_time_span_*() methods in favor of macros.
    • Add macros for GTimeSpan of Day, Hour, Minute, Second and Millisecond.
    • Make GTimeSpan a gint64 rather than a struct.
    • Rename g_date_time_parse_exact() to g_date_time_parse_with_format().
    • Remove g_date_time_get_timezone() as g_date_time_printf() can provides this.
    • Rename g_date_time_humanize() to g_date_time_format_for_display().
    • Make GDateTime reference counted.
    Monday, October 5, 2009 at 3:05 am #
  13. monodanmorg wrote:

    Can you add a function to get the last day of a month or the date being the last date of a month if you pass in a date?

    This would also handle leap years too.

    02/15/2008 –> 02/29/2008

    02/15/2009 –> 02/28/2009

    Or either pass in the month and year.

    Friday, October 30, 2009 at 2:41 pm #
  14. monodanmorg wrote:

    See the private function:

    static gint
    days_in_month (gint year,
    gint month)

    Can we make this a public function as g_date_time_days_in_month ?

    Thursday, November 5, 2009 at 7:45 pm #
  15. Geert wrote:

    Suggestion:
    Since time_t can be 32 or 64 bits the rounding to the nearest representable value can be larger theb 2037.

    time_t g_date_time_to_time_t (GDateTime *datetime)

    2037)

    > else if ( year > 2037 && (sizeof(time_t) == sizeof(guint32)))

    Sunday, January 17, 2010 at 6:39 am #
  16. Geert wrote:

    The API as it is does not allow proper serialization and deserialization.
    I would suggest to change the boolean “is_utc” to a integer “utc_offset”.
    When in utc the utc_offset would be 0 other the utc_offset should contain the correct offset in respect to DST.

    As an example :

    if (d1.is_utc == d2.is_utc)
    {
    diff = d2-d1;
    }
    else if (d1.is_utc != d2.is_utc)
    {
    if (!d1.is_utc) d1.to_utc;
    if (!d2.is_utc) d2.to_utc;
    diff = d2-d1;
    }

    Alternatively :

    is_utc = (utc_offset == 0);
    diff = (d2-d2.utc_offset) – (d1-d1.utc_offset);

    1. The API for g_date_time_diff is not clear.
    If the difference should be in absolute nanoseconds then the “g_date_time_diff” function
    should assure that the difference is made between times with the same “is_utc” flag or as suggested above utc_offset.

    2. g_date_time_to_time_t : Should the GDateTime not be converted to UTC before returning the time_t?
    3. g_date_time_to_timeval : Should the GDateTime not be converted to UTC before returning the timeval?

    Sunday, January 17, 2010 at 8:49 am #
  17. chergert wrote:

    This was completely rewritten based on comments from the gnome bugzilla.

    See: http://github.com/chergert/gdatetime

    Sunday, January 17, 2010 at 5:07 pm #