关于日期:如何使用Groovy的.format()方法显示本地时间?

How do I display local time with Groovy's .format() method?

我有一组用以下代码(我不能更改)保存到数据库的日期:

1
2
Date date = new Date()
save(date)

groovy中是否没有干净的方法可以重新格式化并在用户的本地时区中显示日期?如...

1
dateCreated.format('h:mm a MMMM dd, yyyy', Locale.US)

与Groovy内建的功能完全不同吗?是唯一的解决方案吗?

1
2
3
4
5
6
7
import java.text.SimpleDateFormat

String date = dateCreated.format('h:mm a MMMM dd, yyyy')
def fmt = new SimpleDateFormat('h:mm a MMMM dd, yyyy', Locale.US);
Date local_time = fmt.parse(date);
String formatted_local = local_time.format('h:mm a MMMM dd, yyyy')
formatted_local

Groovy日期文档:http://docs.groovy-lang.org/latest/html/groovy-jdk/java/util/Date.html#format(java.lang.String)

参考:如何使用Java中的DateFormat解析月份的完整形式的字符串?


在Groovy中应该非常简单。

假设,使用以下语句保存日期

1
2
def date = new Date()
println date

输出

1
Sun Apr 16 11:10:14 UTC 2017

如果您需要将其转换为具有特定日期时间格式的特定时区,只需使用以下语句

1
println date.format('yyyy/MM/dd HH:mm', TimeZone.getTimeZone('IST'))

将显示输出:

1
2017/04/16 16:40

注意:来源采用UTC格式,并将现有日期转换为IST格式。

如果需要日期对象(不是上面提到的字符串),请使用以下内容:

1
2
3
4
5
6
7
def date = new Date()
def dtFormat ="yyyy-MM-dd'T'HH:mm:ssZ"
def dt = date.format(dtFormat, TimeZone.getTimeZone('IST'))
assert dt instanceof String

def newDate = Date.parse(dtFormat, dt)
assert newDate instanceof Date

您可以快速在线尝试Demo


tl; dr

1
2
3
4
ZonedDateTime.parse (
   "Mon Apr 03 16:49:56 PDT 2017" ,
    DateTimeFormatter.ofPattern ("EEE MMM dd HH:mm:ss z uuuu", Locale.US )
)

句法

抱歉,我不知道Groovy语法,所以这是Java语法。

java.util.Date::toString

您是说通过调用java.util.Date::toString将值作为文本数据类型保存到数据库中吗?

因此,现在您需要以java.util.Date::toString使用的默认格式(例如Mon Apr 03 16:49:56 PDT 2017)解析字符串,以返回到日期时间对象。

首先,您必须已经知道这是一种存储日期时间值的可怕方法。该格式假定为英语,并且舍弃任何小数秒。这种格式很难被人阅读,也很难被机器解析。它使用伪时区的3-4个字母缩写,例如PDTIST,它们不是真实的时区,不是标准化的,甚至不是唯一的(!)。正确的时区名称,格式为continent/region,例如America/MontrealAfrica/CasablancaPacific/Auckland

ISO 8601

相反,当序列化日期时间值时,请使用标准ISO 8601格式。

在解析和生成字符串时,默认情况下java.time类使用标准ISO 8601格式。

避免使用旧的日期时间类

知道java.util.Date是与Java最早版本捆绑在一起的麻烦的,设计不良的,令人困惑的旧日期时间类之一。这些类现在已被遗留,由java.time类取代。避免使用遗留类,请改用java.time。

使用java.time

DateTimeFormatter类分析字符串。我们必须定义一个格式化模式以匹配Date::toString的输出。

1
2
String input ="Mon Apr 03 16:49:56 PDT 2017" ;
DateTimeFormatter f = DateTimeFormatter.ofPattern ("EEE MMM dd HH:mm:ss z uuuu", Locale.US ) ;

现在我们可以将该字符串解析为ZonedDateTime

1
ZonedDateTime zdt = ZonedDateTime.parse ( input, f ) ;

zdt.toString(): 2017-04-03T16:49:56-07:00[America/Los_Angeles]

通常,序列化日期时间值以进行数据存储和交换的最佳实践是将值保留在UTC中,然后以标准ISO 8601格式创建字符串。 ISO 8601中UTC的约定是附加Z(Zulu的缩写),意思是UTC。

Instant类表示UTC时间轴上的时刻,其分辨率为纳秒(最多十进制的九(9)位数字)。

1
2
Instant instant = zdt.toInstant() ;
String output = instant.toString() ;

instant.toString(): 2017-04-03T23:49:56Z

JDBC

您的问题和评论不清楚。如果您使用适当的日期时间类型将值存储在数据库中,则无需像上面讨论的那样去处理字符串。如果存储正确,则应让JDBC驱动程序完成在必要时进行数据进出数据库的操作。

符合JDBC 4.2及更高版本的驱动程序可以通过PreparedStatement::setObjectResultSet::getObject直接使用java.time类型。

关于java.time

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