10

This is probably too much to ask, but is there any language that does a really terrific job of representing time and date operations? I'll grant straight away that it's really hard to write a truly great time library. That said, are there any widespread languages that have one? Basically, I want something that handles time and date as comprehensively as modern regular expression libraries do their jobs. Everything I've seen so far in Python and Java omits one or more pretty important pieces, or makes too many things hard.

At least this should be intuitive to do:

  • find the number of days between two given dates, number of minutes between two given minute periods, etc.
  • add and subtract intervals from timestamps
  • allow simple conversion between timezones, with Daylight Saving Time changes by region automatically accounted for (given that there's an accurate supporting database of regional settings available)
  • get the period that a given timestamp falls into, given period granularity ("what calendar day is this date in?")
  • support very general string-to-date conversions (given a pattern)

Further, if there's a Java-style Calendar/GregorianCalendar setup, the general Calendar class should be accommodating toward subclasses if I need to roll my own Hebrew, Babylonian, Tolkien, or MartianCalendar. (Java Calendars make this pointlessly hard, for example.)

I am completely language-agnostic here. It's fine if the thing chokes on computing ambiguous stuff like "how many minutes are there between 2002 and next Valentine's Day?"

Motti
  • 110,860
  • 49
  • 189
  • 262

15 Answers15

8

How about .NET's DateTime? (You can pick your language within the framework)

Eugene Yokota
  • 94,654
  • 45
  • 215
  • 319
  • 1
    I suspect you will find the [*NodaTime*](https://nodatime.org) library to be superior for .Net programming. Based on the highly successful [*Joda-Time*](https://www.joda.org/joda-time/) project for Java. – Basil Bourque Apr 12 '19 at 23:14
5

Are you looking for something like PHPs strtotime? That will give you the unix timestamp of almost anything you can throw at it.

From the php site:

<?php
echo strtotime("now"), "\n";
echo strtotime("10 September 2000"), "\n";
echo strtotime("+1 day"), "\n";
echo strtotime("+1 week"), "\n";
echo strtotime("+1 week 2 days 4 hours 2 seconds"), "\n";
echo strtotime("next Thursday"), "\n";
echo strtotime("last Monday"), "\n";
?>

.NET's date classes require much more arcane fiddling with DateTimeFormatInfo and the like to parse date strings that aren't nearly as complicated as strtotime can handle.

PHP provides a DateTime class and a DateTimeZone class as of PHP 5, but they're both quite poorly documented. I still mostly use unix timestamps and the date, time and strtotime functions as I haven't fully come to grips with the new objects.

The following links attempt to flesh out DateTime and DateTimeZone a bit better:

Shabbyrobe
  • 12,298
  • 15
  • 60
  • 87
3

For Java, I highly recommend the Joda Date/Time library.

MetroidFan2002
  • 29,217
  • 16
  • 62
  • 80
  • FYI, the [*Joda-Time*](http://www.joda.org/joda-time/) project is now in [maintenance mode](https://en.wikipedia.org/wiki/Maintenance_mode), advising migration to the [*java.time*](http://docs.oracle.com/javase/10/docs/api/java/time/package-summary.html) classes. See [Tutorial by Oracle](https://docs.oracle.com/javase/tutorial/datetime/TOC.html). – Basil Bourque Apr 12 '19 at 23:11
3

You might want to check the Date::Manip Perl module on CPAN.

zoul
  • 102,279
  • 44
  • 260
  • 354
3

There is a really cool programming language called Frink. It supports pretty much every unit ever invented, every physical or mathematical constant, timezones, bla bla bla …

It even has a web interface and a Java Applet.

Some of your challenges above:

  • find the number of days between two given dates, number of minutes between two given minute periods, etc.
    • How many days till Christmas: # 2008-12-25 # - now[] -> days
    • How long since noon: now[] - # 12:00 # -> minutes
  • add and subtract intervals from timestamps
    • When was my million minutes birthday: # 1979-01-06 # + 1 million minutes
  • allow simple conversion between timezones, with Daylight Saving Time changes by region automatically accounted for (given that there's an accurate supporting database of regional settings available)
    • When did the Beijing Olympics start in London: # 2008-08-08 08:08 PM China # -> London
  • support very general string-to-date conversions (given a pattern)
    1. Define a new date format: ### dd.MM.yyyy ###
    2. Parse: # 18.09.2008 #

Frink integrates nicely with Java: it can be embedded in Java applications and Frink programs can call Java code.

Jörg W Mittag
  • 363,080
  • 75
  • 446
  • 653
2

java.time

The industry-leading date-time framework is java.time, built into Java 8 and later, defined by JSR 310.

The man leading this project is Stephen Colebourne. He also led its predecessor, the very successful Joda-Time project. The lessons learned with Joda-Time were applied in designing the all-new java.time classes. By the way, Joda-Time was ported to .Net in the NodaTime project.

find the number of days between two given dates,

Use the Period class to represent a span-of-time in granularity of years-months-days.

LocalDate start = LocalDate.of( 2019 , Month.JANUARY , 23 ) ;
LocalDate stop = LocalDate.of( 2019 , Month.MARCH , 3 ) ;
Period p = Period.between( start , stop ) ;

Or if you want just want a total count of days, use ChronoUnit.

long days = ChronoUnit.DAYS.between( start , stop ) ;

number of minutes between two given minute periods, etc.

Use Duration class to represent a span-of-time in granularity of days (24-hour chunks of time unrelated to calendar), hours, minutes, seconds, fractional second.

Instant start = Instant.now() ;    // Capture the current moment as seen in UTC.
…
Instant stop = Instant.now() ;
Duration d = Duration.between( start , stop ) ;

If you want total number of minutes elapsed of the entire span-of-time, call toMinutes.

long elapsedMinutes = d.toMinutes() ;

add and subtract intervals from timestamps

You can do date-time math using the Period and Duration classes mentioned above, passing to plus & minus methods on various classes.

Instant now = Instant.now() ;
Duration d = Duration.ofMinutes( 7 ) ;
Instant later = now.plus( d ) ;

allow simple conversion between timezones, with Daylight Saving Time changes by region automatically accounted for

The ZoneId class stores a history of past, present, and future changes to the offset used by people of a specific region, that is, a time zone.

Specify a proper time zone name in the format of Continent/Region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 2-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).

ZoneId z = ZoneId.of( "America/Montreal" ) ;  
LocalDate today = LocalDate.now( z ) ;        // Get the current date as seen by the people of a certain region. 

If you want to use the JVM’s current default time zone, ask for it and pass as an argument. If omitted, the code becomes ambiguous to read in that we do not know for certain if you intended to use the default or if you, like so many programmers, were unaware of the issue.

ZoneId z = ZoneId.systemDefault() ;  // Get JVM’s current default time zone.

We can use the ZoneId to adjust between zones. First, let's get the current moment as seen in UTC.

Instant instant = Instant.now() ;

Apply a time zone for the time zone in Tunisia. Apply a ZoneId to the Instant to yield a ZonedDateTime object. Same moment, same point on the timeline, but a different wall-clock time.

ZoneId zTunis = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdtTunis = instant.atZone( zTunis ) ;

Let us see the same moment as it would appear to someone in Japan who is looking up at the clock on their wall.

ZoneId zTokyo = ZoneId.of( "Asia/Tokyo" ) ;
ZonedDateTime zdtTokyo = zdtTunis.withZoneSameInstant( zTokyo ) ;  // Same moment, different wall-clock time.

All three objects, instant, zdtTunis, and zdtTokyo all represent the same moment. Imagine a three-way conference call between someone in Iceland (where they use UTC), someone in Tunisia, and someone in Japan. If each person at the same moment looks up at the clock and calendar on their respective wall, they will each see a different time-of-day on their clock and possibly a different date on their calendar.

Notice that java.time uses immutable objects. Rather than change (“mutate”) an object, return a fresh new object based on the original’s values.

(given that there's an accurate supporting database of regional settings available)

Java includes a copy of tzdata, the standard time zone database. Be sure to keep your JVM up-to-date to carry current time-zone definitions. Unfortunately, politicians around the globe have shown a penchant for redefining the time zone(s) of their jurisdiction with little or no advance warning. So you may need update the tzddata manually if a time zone you care about changes suddenly.

By the way, your operating system likely carries its own copy of tzdata as well. Keep that fresh for your non-Java needs. Ditto for any other systems you may have installed such as a database server like Postgres with its own copy of tzdata.

get the period that a given timestamp falls into, given period granularity ("what calendar day is this date in?")

By “calendar day”, do you mean day-of-week? In java.time, we have DayOfWeek enum that predefines seven objects, one for each day of the week.

DayOfWeek dow = LocalDate.now( z ).getDayOfWeek() ;

By “calendar day”, do you mean the day of the year (1-366)?

int dayOfYear = LocalDate.now( z ).getDayOfYear() ;

By “calendar day”, do you mean a representation of the year-month?

YearMonth ym = YearMonth.from( today ) ;  // `today` being `LocalDate.now( ZoneId.of( "Pacific/Auckland" ) )`. 

Perhaps month-day?

MonthDay md = MonthDay.from( today ) ;

support very general string-to-date conversions (given a pattern)

You can specify a custom formatting pattern to use in parsing/generating string that represent the value of a date-time object. See the DateTimeFormatter.ofPattern method. Search Stack Overflow for more info, as this has been handled many many times.

If your string is properly formatted by the localization rules for a particular culture, you can let java.time do the work of parsing without bothering to define a formatting pattern.

Locale locale = Locale.CANADA_FRENCH ; 
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDate( FormatStyle.MEDIUM ).withLocale( locale ) ;
String output = LocalDate.now( z ).format( f ) ; 

if there's a Java-style Calendar/GregorianCalendar setup

The Calendar and GregorianCalendar classes bundled with the earliest versions of Java are terrible. Never use them. They are supplanted entirely by the java.time classes, specifically the ZonedDateTime class.

accommodating toward subclasses if I need to roll my own Hebrew, Babylonian, Tolkien, or MartianCalendar. (Java Calendars make this pointlessly hard, for example.)

Many calendaring systems have already been implemented for java.time. Each is known as a chronology. The calendaring system commonly used in the West and in much business around the globe, is the ISO 8601 chronology. This is used by default in java.time, java.time.chrono.IsoChronology.

Bundled with Java you will also find additional chronologies including the Hijrah version of the Islamic calendar, the Japanese Imperial calendar system, Minguo calendar system (Taiwan, etc.), and the Thai Buddhist calendar.

You will find more chronologies defined in the ThreeTen-Extra project. See the org.threeten.extra.chrono package for a list including: IRS/IFRS standard accounting calendar, British Julian-Gregorian cutover calendar system, Coptic Christian calendar, the Discordian calendar system, Ethiopic calendar, the International Fixed calendar (Eastman Kodak calendar), Julian calendar, and more.

But if you need some other calendar, java.time provides the AbstractChronology to get you started. But do some serious web-searching before embarking on your own, as it may already be built. And all the above listed chronologies are open-source, so you can study them for guidance.

"how many minutes are there between 2002 and next Valentine's Day?"

LocalDate date2002 = Year.of( 2002 ).atDay( 1 );

MonthDay valentinesHoliday = MonthDay.of( Month.FEBRUARY , 14 );

ZoneId z = ZoneId.of( "America/Edmonton" );
LocalDate today = LocalDate.now( z );
LocalDate valDayThisYear = today.with( valentinesHoliday );
LocalDate nextValDay = valDayThisYear;
if ( valDayThisYear.isBefore( today ) )
{ // If Valentine's day already happened this year, move to next year’s Valentine's Day.
    nextValDay = valDayThisYear.plusYears( 1 );
}

ZonedDateTime start = date2002.atStartOfDay( z );
ZonedDateTime stop = nextValDay.atStartOfDay( z );
Duration d = Duration.between( start , stop );
long minutes = d.toMinutes();

System.out.println( "From start: " + start + " to stop: " + stop + " is duration: " + d + " or a total in minutes: " + minutes + "." );
LocalDate date2002 = Year.of( 2002 ).atDay( 1 );

MonthDay valentinesHoliday = MonthDay.of( Month.FEBRUARY , 14 );

ZoneId z = ZoneId.of( "America/Edmonton" );
LocalDate today = LocalDate.now( z );
LocalDate valDayThisYear = today.with( valentinesHoliday );
LocalDate nextValDay = valDayThisYear;
if ( valDayThisYear.isBefore( today ) )
{ // If Valentine's day already happened this year, move to next year’s Valentine's Day.
    nextValDay = valDayThisYear.plusYears( 1 );
}

ZonedDateTime start = date2002.atStartOfDay( z );
ZonedDateTime stop = nextValDay.atStartOfDay( z );
Duration d = Duration.between( start , stop );
long minutes = d.toMinutes();

System.out.println( "From start: " + start + " to stop: " + stop + " is duration: " + d + " or a total in minutes: " + minutes + "." );

When run.

From start: 2002-01-01T00:00-07:00[America/Edmonton] to stop: 2020-02-14T00:00-07:00[America/Edmonton] is duration: PT158832H or a total in minutes: 9529920.


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
2

I like .NET for this. It provides good Date/Time manipulation, with the DateTime and Timespan classes. However, most date/time stuff is fairly simple in any language which will give you a unix timestamp to work with.

J D OConal
  • 624
  • 4
  • 14
  • .NET is OK, but some of the details are confusing. – EndangeredMassa Sep 18 '08 at 05:46
  • What did you find confusing? It was entirely intuitive to me. Maybe post a question here. – Justin R. Jan 16 '09 at 05:41
  • *most date/time stuff is fairly simple* — I could not disagree more. The more you know you learn about date-time handling, the more you realize how tricky and slippery the subject is. If you think date-time handling can be done just by adding long long integers, you need to do some more study. – Basil Bourque Apr 12 '19 at 23:15
2

PHP is not half bad.

// given two timestamps: $t1, and $t2:

// find the number of days between two given dates, number of minutes
// between two given minute periods, etc.  
$daysBetween = floor(($t2 - $t1) / 86400);  // 86400 = 1 day in seconds
$hoursBetween = floor(($t2 - $t1) / 3600);  // 3600 = 1 hour in seconds

// add and subtract intervals from timestamps  
$newDate = $t1 + $interval;

// allow simple conversion between timezones, with Daylight Saving Time
// changes by region automatically accounted for (given that there's an
// accurate supporting database of regional settings available)

// See PHP's Calendar functions for that
// http://au2.php.net/manual/en/book.calendar.php
// It not only supports basic stuff like timezones and DST, but also
// different types of calendar: French, Julian, Gregorian and Jewish.

// get the period that a given timestamp falls into, given period
// granularity ("what calendar day is this date in?")  
if (date("d", $t1) == 5)    // check if the timestamp is the 5th of the month
if (date("h", $t1) == 16)   // is it 4:00pm-4:59pm ?

// support very general string-to-date conversions (given a pattern) 

// strtotime() is magic for this. you can just type in regular english
// and it figures it out. If your dates are stored in a particular format
// and you want to convert them, you can use strptime()

You gotta give it some kudos for having a function to tell what date Easter is in a given year.

nickf
  • 537,072
  • 198
  • 649
  • 721
2

For C++, there's Boost.Date_Time.

KTC
  • 8,967
  • 5
  • 33
  • 38
1

Perl's DateTime library is without a doubt the best (as in most correct) library for handling datetime math, and timezones. Everything else is wrong to varying degrees. (and I say this having written the above referenced blog post on PHP's DateTime/DateTimeZone libraries)

kellan
  • 394
  • 1
  • 5
1

PHP Date function is fantastic and has lots of helpful functions (link: php.net/date )

.NET is not bad in it's latest releases plus i like the fact you can add a reference to a secondary language and mix and match the code in your project. So you could use C# and VB functions within the same class.

Mat
  • 202,337
  • 40
  • 393
  • 406
Andrew
  • 9,967
  • 10
  • 64
  • 103
1

My personal favourite would be Ruby with Rails' ActiveSupport.

start_time = 5.months_ago.at_end_of_week 
end_time =  6.months.since(start_time)

It supports all of the features you've mentioned above with a similar DSL (domain specific language)

Motti
  • 110,860
  • 49
  • 189
  • 262
Redbeard
  • 988
  • 5
  • 8
1

I agree that Java SDK has a terrible implementation of datetime library. Hopefully JSR 310 will fix this problem in Java 7. If you can't wait for Java 7, I would recommend the precursor to JSR-310, Joda Time.

I agree that Ruby on Rails implementation in ActiveSupport is an excellent implementation that gets the basics right.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
Alan
  • 7,066
  • 5
  • 30
  • 38
  • For the record, [JSR 310](https://jcp.org/en/jsr/detail?id=310) was finally implemented in Java 8 and later, in the *java.time* classes. – Basil Bourque Apr 12 '19 at 23:12
  • FYI, the [*Joda-Time*](http://www.joda.org/joda-time/) project is now in [maintenance mode](https://en.wikipedia.org/wiki/Maintenance_mode), advising migration to the [*java.time*](http://docs.oracle.com/javase/10/docs/api/java/time/package-summary.html) classes. See [Tutorial by Oracle](https://docs.oracle.com/javase/tutorial/datetime/TOC.html). – Basil Bourque Apr 12 '19 at 23:12
1

I've been quite happy with the PEAR Date class for PHP. It does everything you're asking about, I believe, with the exception of multiple calendars, although there's also Date_Human, which could be a template for that sort of thing.

Also, I haven't worked with it yet, but Zend_Date, also for PHP, looks like it will work well for most of what you want. Zend_Date has the advantage of being based on Unix timestamps and the fact that the bulk of Zend Framework classes are intended to be easy to extend. So most likely you could quickly add support for your other date systems by extending Zend_Date.

Michael Johnson
  • 2,287
  • 16
  • 21
0

Ruby has excellent support, actually. Check out this page. Really great support for turning strings into dates, dates into strings, doing math on dates, parsing "natural language" strings like "3 months ago this friday at 3:45pm" into an actual date, turning dates into strings so you can do stuff like "Sam last logged in 4 days ago" or whatever...

Very nifty.

Cody Hatch
  • 8,857
  • 6
  • 29
  • 36