什么语言的日期,时间和日历操作真的很好?

问题描述 投票:9回答:15

这可能是一个问题太多了,但有没有任何语言可以表达时间和日期操作的非常好的工作?我马上就会批准写一个真正伟大的时间库真的很难。那就是说,有没有广泛的语言有一个?基本上,我想要像现代正则表达式库那样全面地处理时间和日期。到目前为止,我在Python和Java中看到的所有内容都省略了一个或多个非常重要的部分,或者使得太多的事情变得困难。

至少这应该是直观的:

  • 查找两个给定日期之间的天数,两个给定分钟周期之间的分钟数等。
  • 从时间戳添加和减去间隔
  • 允许在时区之间进行简单转换,并按区域自动更改夏令时更改(假设有可用的区域设置的准确支持数据库)
  • 获得给定时间戳落入的时间段,给定时间段粒度(“这个日期是哪个日历日?”)
  • 支持非常通用的字符串到目前的转换(给定模式)

此外,如果有一个Java风格的Calendar / GregorianCalendar设置,如果我需要滚动自己的希伯来语,巴比伦语,Tolkien或MartianCalendar,一般的Calendar类应该适应子类。 (例如,Java Calendars使这一点变得毫无意义。)

我在这里完全与语言无关。如果事情在计算模糊的东西,比如“2002年和下一个情人节之间有多少分钟?”,那就没关系了。

datetime time language-features date
15个回答
7
投票

.NET's DateTime怎么样? (您可以在框架内选择您的语言)


1
投票

毫无疑问,Perl的DateTime库是处理日期时间数学和时区的最佳(最正确的)库。其他一切都在不同程度上是错误的。 (我说这是在PHP的DateTime / DateTimeZone库上编写了上面引用的博客文章)


1
投票

我个人最喜欢的是Ruby with Rails的ActiveSupport。

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

它支持您在上面提到的所有类似DSL(特定于域的语言)的功能


1
投票

PHP日期函数很棒,有很多有用的功能(链接:php.net/date

.NET在它的最新版本中也不错,而且我喜欢你可以添加对辅助语言的引用并混合和匹配项目中的代码。所以你可以在同一个类中使用C#和VB函数。


1
投票

我同意Java SDK有一个糟糕的datetime库实现。希望JSR 310将在Java 7中解决这个问题。如果你不能等待Java 7,我会推荐JSR-310,Joda Time的前身。

我同意ActiveSupport中的Ruby on Rails实现是一个很好的实现,可以很好地掌握基础知识。


1
投票

java.time

业界领先的日期时间框架是java.time,内置于Java 8及更高版本,由JSR 310定义。

领导这个项目的人是Stephen Colebourne。他还领导了它的前身,非常成功的Joda-Time项目。使用Joda-Time学到的经验教训应用于设计全新的java.time类。顺便说一句,Joda-Time在NodaTime项目中被移植到.Net。

找到两个给定日期之间的天数,

使用Period类来表示以年 - 月 - 日为单位的粒度。

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

或者,如果您只想要总天数,请使用ChronoUnit

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

两个给定分钟周期之间的分钟数等

使用Duration类来表示粒度天数(与日历无关的24小时时间块),小时,分钟,秒,小数秒的时间跨度。

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

如果您想要整个时间跨度的总分钟数,请致电toMinutes

long elapsedMinutes = d.toMinutes() ;

从时间戳添加和减去间隔

您可以使用上面提到的PeriodDuration类进行日期时间数学运算,并在各种类上传递plusminus方法。

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

允许在时区之间进行简单转换,并按区域自动更改夏令时更改

ZoneId类存储特定区域的人(即时区)使用的偏移的过去,现在和将来的变化的历史。

proper time zone name的格式指定Continent/Region,例如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用2-4字母缩写,如ESTIST,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

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

如果要使用JVM的当前默认时区,请求它并作为参数传递。如果省略,代码变得模糊不清,因为我们不确定您是否打算使用默认值,或者如果您像许多程序员一样,不知道这个问题。

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

我们可以使用ZoneId来调整区域。首先,让我们看看UTC中的当前时刻。

Instant instant = Instant.now() ;

在突尼斯为时区应用时区。将ZoneId应用于Instant以产生ZonedDateTime物体。同一时刻,时间轴上的相同点,但是不同的挂钟时间。

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

让我们看到日本人在墙上看钟的时刻。

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

所有三个对象,instantzdtTuniszdtTokyo都代表同一时刻。想象一下,冰岛某人(他们使用UTC),突尼斯某人和日本某人之间的三方电话会议。如果每个人在同一时刻都在他们各自的墙上查看时钟和日历,他们每个人都会在他们的时钟上看到不同的时间,并且可能在他们的日历上看到不同的日期。

请注意,java.time使用immutable objects。而不是更改(“变异”)对象,而是根据原始值返回一个新的新对象。

(鉴于有可用的区域设置的准确支持数据库)

Java包含标准时区数据库tzdata的副本。请务必使JVM保持最新,以便携带当前的时区定义。不幸的是,世界各地的政治家都表示喜欢重新定义其管辖区的时区,很少或根本没有预先警告。因此,如果您关心的时区突然发生变化,您可能需要手动更新tzddata。

顺便说一句,您的操作系统也可能带有自己的tzdata副本。保持新鲜,满足您的非Java需求。同样适用于您可能安装的任何其他系统,例如Postgres等数据库服务器及其自己的tzdata副本。

获得给定时间戳落入的时间段,给定时间段粒度(“这个日期是哪个日历日?”)

到“日历日”,你的意思是星期几?在java.time中,我们有DayOfWeek枚举,它预定义七个对象,一个星期的每一天。

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

到“日历日”,你的意思是一年中的哪一天(1-366)?

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

到“日历日”,你的意思是year-month的代表?

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

也许是一个月?

MonthDay md = MonthDay.from( today ) ;

支持非常通用的字符串到目前的转换(给定模式)

您可以指定自定义格式设置模式,以用于解析/生成表示日期时间对象值的字符串。请参阅DateTimeFormatter.ofPattern方法。搜索Stack Overflow获取更多信息,因为这已被处理了很多次。

如果您的字符串由特定文化的本地化规则正确格式化,您可以让java.time完成解析工作,而无需定义格式化模式。

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

如果有Java风格的Calendar / GregorianCalendar设置

与最早版本的Java捆绑在一起的CalendarGregorianCalendar类很糟糕。切勿使用它们。它们完全被java.time类取代,特别是ZonedDateTime类。

如果我需要滚动我自己的希伯来语,巴比伦语,托尔金语或MartianCalendar,则适应子类。 (例如,Java Calendars使这一点变得毫无意义。)

许多日历系统已经为java.time实现。每个都被称为年表。西方常用的日历系统和全球许多业务都是ISO 8601年表。默认情况下,这在java.time,java.time.chrono.IsoChronology中使用。

与Java捆绑在一起,您还可以找到其他年代表,包括伊斯兰历法的Hijrah版本,日本帝国日历系统,Minguo日历系统(台湾等)和Thai Buddhist日历。

您将在ThreeTen-Extra项目中找到更多的年表。请参阅org.threeten.extra.chrono包裹,其中包括:IRS / IFRS标准会计日历,英国Julian-Gregorian切换日历系统,科普特基督教日历,Discordian日历系统,Ethiopic日历,International Fixed calendar (Eastman Kodak calendar),Julian日历等。

但是如果您需要其他日历,java.time会提供AbstractChronology来帮助您入门。但是在开始自己之前做一些严肃的网络搜索,因为它可能已经建成了。以上列出的所有年表都是开源的,因此您可以将它们作为指导进行研究。

“2002年和下一个情人节之间有多少分钟?”

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 + "." );

跑步时

从开始:2002-01-01T00:00-07:00 [美国/埃德蒙顿]停止:2020-02-14T00:00-07:00 [美国/埃德蒙顿]持续时间:PT158832H或总分钟数:9529920。


About java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,如java.util.DateCalendarSimpleDateFormat

要了解更多信息,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规格是JSR 310

现在在Joda-Timemaintenance mode项目建议迁移到java.time班。

您可以直接与数据库交换java.time对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*类。

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展了java.time。该项目是未来可能添加到java.time的试验场。你可能会在这里找到一些有用的类,如IntervalYearWeekYearQuartermore


0
投票

实际上,Ruby有很好的支持。看看this page。非常支持将字符串转换为日期,将日期转换为字符串,在日期上进行数学运算,将“自然语言”字符串(如“3个月前的这个星期五下午3:45”)解析为实际日期,将日期转换为字符串以便您可以执行某些操作比如“Sam最后一次登录4天前”或者其他......

非常漂亮。


4
投票

你在寻找像PHPs strtotime这样的东西吗?这将为您提供几乎任何可以投入的unix时间戳。

来自php网站:

<?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的日期类需要更加神秘的摆弄DateTimeFormatInfo等来解析日期字符串,这些字符串并不像strtotime那样复杂。

从PHP 5开始,PHP提供了一个DateTime类和一个DateTimeZone类,但它们的文档都很差。我仍然主要使用unix时间戳和datetimestrtotime函数,因为我还没有完全掌握新对象。

以下链接尝试更好地充实DateTime和DateTimeZone:


3
投票

对于Java,我强烈推荐Joda Date/Time library


3
投票

您可能想要检查CPAN上的Date::Manip Perl模块。


3
投票

有一种非常酷的编程语言叫做Frink。它支持几乎所有发明的单位,每个物理或数学常数,时区,bla bla bla ...

它甚至有一个web interfaceJava Applet

您面临的一些挑战:

  • 查找两个给定日期之间的天数,两个给定分钟周期之间的分钟数等。 圣诞节前几天:# 2008-12-25 # - now[] -> days 中午多久:now[] - # 12:00 # -> minutes
  • 从时间戳添加和减去间隔 我百万分钟的生日是什么时候:# 1979-01-06 # + 1 million minutes
  • 允许在时区之间进行简单转换,并按区域自动更改夏令时更改(假设有可用的区域设置的准确支持数据库) 北京奥运会什么时候在伦敦开始的:# 2008-08-08 08:08 PM China # -> London
  • 支持非常通用的字符串到目前的转换(给定模式) 定义新的日期格式:### dd.MM.yyyy ### 解析:# 18.09.2008 #

Frink与Java很好地集成:它可以是embedded in Java applications和Frink程序可以call Java code


2
投票

我喜欢.NET。它使用DateTime和Timespan类提供了良好的日期/时间操作。但是,大多数日期/时间的东西在任何语言中都相当简单,它会为你提供一个unix时间戳。


2
投票

PHP不是一半坏。

// 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()

你必须给a function to tell what date Easter is in a given year一些荣誉。


2
投票

对于C ++,有Boost.Date_Time


1
投票

我对PHP的PEAR Date类非常满意。我相信,除了多个日历之外,它会做你要问的所有事情,尽管还有Date_Human,它可能是这类事情的模板。

此外,我还没有使用它,但Zend_Date,也适用于PHP,看起来它适用于你想要的大部分。 Zend_Date的优势在于基于Unix时间戳以及大量Zend Framework类易于扩展的事实。因此,您很可能通过扩展Zend_Date来快速添加对其他日期系统的支持。

© www.soinside.com 2019 - 2024. All rights reserved.