在GMT时区中保存和检索日期并转换为字符串

Chi*_*Bud 0 java datetime date datetimeoffset

我有要求

  • 在GMT时区中保存并检索日期(日期应转换为String).因此,如果用户保存日期10/10/2017 23:05,那将保存为10/11/2017 4:05(如果在CST时间保存,例如,提前5小时)在DB中.
  • 在检索和向UI呈现日期时,对于CST用户,它应显示为 10/10/2017 23:05.
  • 此外,需要验证函数以了解日期是否需要以美国/非美国日期格式显示(dd/MM/YYYY与mm/DD/YYYY).

为了达到这个目的,我编写了以下代码片段,但是没有产生所需的结果.它存储的价值为10/11/2017 4:05,然而,当呈现给美国,即获得价值/刷新页面时,它又 增加了5个小时.删除了异常和其他不必要的代码,使其变得简单:

public class DatetoString implements Serializable
{
    private final DateFormat dateFormatter = createDateFormatter();

    // Sets Date to model
    public void setTypedValue(final Object val)
    {
        final String dateValue;
        String dateTimeFormat = BooleanUtils.isFalse(getUSDateFormatConfig()) ? "dd/MM/yyyy HH:mm" : "MM/dd/yyyy HH:mm";
        DateFormat df = new SimpleDateFormat(dateTimeFormat);
        df.setTimeZone(TimeZone.getTimeZone("GMT"));

        Date singleDate = (Date) df.parse(val.toString());
        dateValue = dateFormatter.format(singleDate);
        model.setValue(dateValue.toString());
        // Other code..
    }

    // Retrieves date from model
    public Object getTypedValue()
    {
        final Object result;
        String dateValue = model.iterator().next().getValue();

        String dateTimeFormat = BooleanUtils.isFalse(getUSDateFormatConfig()) ? "dd/MM/yyyy HH:mm" : "MM/dd/yyyy HH:mm";
        DateFormat df = new SimpleDateFormat(dateTimeFormat);
        df.setTimeZone(TimeZone.getTimeZone("GMT"));

        Date singleDate = (Date) df.parse(dateValue);
        result = dateFormatter.format(singleDate);
        return result;
    }

    private DateFormat createDateFormatter()
    {
        final DateFormat result = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
        result.setTimeZone(TimeZone.getTimeZone("GMT"));
        return result;
    }
}
Run Code Online (Sandbox Code Playgroud)

Bas*_*que 5

java.time

您正在使用可怕的旧日期时间类,这些类很麻烦,令人困惑,而且设计很差.它们现在已经遗留下来,取而代之的是java.time类.避免Date,Calendar,SimpleDateFormat,和这样的.

使用实时区域

通过CST您的意思是中部标准时间或中国标准时间?

指定适当的时区名称,格式continent/region,如America/Montreal,Africa/CasablancaPacific/Auckland.切勿使用3-4字母缩写,例如ESTIST因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!).

ZoneId z = ZoneId.of( "America/Chicago" );
Run Code Online (Sandbox Code Playgroud)

与用户确认时区

如果时区对您的工作至关重要,则必须确认其输入所针对的区域.有一些方法可以猜测区域或检测默认值,但重要的是,使区域成为数据输入的一部分以及日期和时间.您可以显示他们选择的列表,或者让他们输入字符串名称.

同上Locale(下面讨论).你可以猜,但如果关键,请问.

解析和组装

在GMT时区中保存并检索日期(日期应转换为String).因此,如果用户保存日期10/10/2017 23:05,那将保存为10/11/2017 4:05(如果在CST时间保存,例如,提前5小时)在DB中.

将用户输入解析为a LocalDateLocalTime使用a DateTimeFormatter.

在实际工作中,您将添加try-catch以捕获DateTimeParseException由错误用户输入引发的内容.

DateTimeFormatter fDate = DateTimeFormatter.ofPattern( "MM/dd/uuuu" ) ;
LocalDate ld = LocalDate.parse( inputDate , f ) ;

DateTimeFormatter fTime = DateTimeFormatter.ISO_LOCAL_TIME ; 
LocalTime lt = LocalTime.parse( inputTime , f ) ;
Run Code Online (Sandbox Code Playgroud)

组合并指定获取ZonedDateTime对象的时区.

ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z ) ;
Run Code Online (Sandbox Code Playgroud)

通过提取Instant始终按UTC定义的UTC来调整为UTC .同一时刻,时间轴上的相同点,但通过不同挂钟的镜头观看.

Instant instant = zdt.toInstant() ;
Run Code Online (Sandbox Code Playgroud)

数据库

在类型的列中保留到您的数据库TIMESTAMP WITH TIME ZONE.另一种类型WITHOUT忽略任何时区或从UTC信息偏移,并且绝对不是您想要跟踪实际时刻的内容.

myPreparedStatement.setObject( … , instant ) ;
Run Code Online (Sandbox Code Playgroud)

从数据库中检索.

Instant instant = myResultSet.getObject( … , Instant.class ) ;
Run Code Online (Sandbox Code Playgroud)

在检索和向UI呈现日期时,对于CST用户,它应显示为10/10/2017 23:05.

调整到用户期望/期望的任何时区.

ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;  // Or "America/Chicago" or "America/Winnipeg" etc.
ZonedDateTime zdt = instant.atZone( z ) ;
Run Code Online (Sandbox Code Playgroud)

生成文本表示

此外,需要验证函数以了解日期是否需要以美国/非美国日期格式显示(dd/MM/YYYY与mm/DD/YYYY).

同样,在生成表示该时刻的文本时,可以Locale根据用户的期望/期望自动进行本地化.

要进行本地化,请指定:

  • FormatStyle 确定字符串的长度或缩写.
  • Locale 确定(a)翻译日期名称,月份名称等的人类语言,以及(b)决定缩写,大写,标点符号,分隔符等问题的文化规范.

例:

Locale l = Locale.FRANCE ;  // Or Locale.US etc.
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.LONG ).withLocale( l ) ;
String output = zdt.format( f ) ;
Run Code Online (Sandbox Code Playgroud)

请注意,Locale时区是正交的,不相关的和分开的.您可以在摩洛哥有一位讲法语的职员跟踪客户在印度的交货情况.因此,该时刻以UTC格式存储在加拿大服务器上运行的数据库中,在数据库和UTC中的其他组件之间进行交换,调整为印度时区以解决客户接收传递的角度,并本地化为法语供用户阅读摩洛哥.


关于java.time

java.time框架是建立在Java 8和更高版本.这些类取代麻烦的老传统日期时间类,如java.util.Date,Calendar,和SimpleDateFormat.

现在处于维护模式Joda-Time项目建议迁移到java.time类.

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

从哪里获取java.time类?

ThreeTen-额外项目与其他类扩展java.time.该项目是未来可能添加到java.time的试验场.您可以在此比如找到一些有用的类Interval,YearWeek,YearQuarter,和更多.