转换给定时区的日期/时间 - java

tra*_*ega 63 java formatting timezone datetime timestamp

我想将此GMT时间戳转换为GMT + 13:

2011-10-06 03:35:05
Run Code Online (Sandbox Code Playgroud)

我尝试过大约100种不同的DateFormat,TimeZone,Date,GregorianCalendar等组合来尝试做这个非常基本的任务.

这段代码完成了我对CURRENT TIME的要求:

Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("GMT"));

DateFormat formatter = new SimpleDateFormat("dd MMM yyyy HH:mm:ss z");    
formatter.setTimeZone(TimeZone.getTimeZone("GMT+13"));  

String newZealandTime = formatter.format(calendar.getTime());
Run Code Online (Sandbox Code Playgroud)

但我想要的是设定时间而不是使用当前时间.

我发现任何时候我都尝试设置这样的时间:

calendar.setTime(new Date(1317816735000L));
Run Code Online (Sandbox Code Playgroud)

使用本地机器的TimeZone.这是为什么?我知道当"new Date()"返回UTC + 0时,为什么当你设置Time以毫秒为单位时,它不再假设时间是UTC?

有可能:

  1. 设置对象的时间(日历/日期/时间标准)
  2. (可能)设置初始时间戳的时区(calendar.setTimeZone(...))
  3. 使用新的TimeZone格式化时间戳(formatter.setTimeZone(...)))
  4. 返回具有新时区时间的字符串.(formatter.format(calendar.getTime()))

在此先感谢您的帮助:D

Cha*_*ton 45

对我来说,最简单的方法是:

Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

//Here you say to java the initial timezone. This is the secret
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
//Will print in UTC
System.out.println(sdf.format(calendar.getTime()));    

//Here you set to your timezone
sdf.setTimeZone(TimeZone.getDefault());
//Will print on your default Timezone
System.out.println(sdf.format(calendar.getTime()));
Run Code Online (Sandbox Code Playgroud)

  • 如何获得实际的日期而不是字符串? (3认同)

小智 30

了解计算机时间的工作原理非常重要.有了这个说我同意,如果创建一个API来帮助您像实时一样处理计算机时间,那么它应该以允许您像实时一样对待它的方式工作.在大多数情况下都是这种情况,但有一些重要的疏忽需要注意.

无论如何我离题!如果您有UTC偏移(最好在UTC中工作而不是GMT偏移),您可以计算时间(以毫秒为单位)并将其添加到时间戳中.请注意,SQL时间戳可能与Java时间戳不同,因为计算时间的过程并不总是相同的 - 这取决于数据库技术和操作系统.

我建议您使用System.currentTimeMillis()作为时间戳,因为这些可以在java中更一致地处理,而不必担心将SQL时间戳转换为Java Date对象等.

要计算您的偏移量,您可以尝试这样的事情:

Long gmtTime =1317951113613L; // 2.32pm NZDT
Long timezoneAlteredTime = 0L;

if (offset != 0L) {
    int multiplier = (offset*60)*(60*1000);
    timezoneAlteredTime = gmtTime + multiplier;
} else {
    timezoneAlteredTime = gmtTime;
}

Calendar calendar = new GregorianCalendar();
calendar.setTimeInMillis(timezoneAlteredTime);

DateFormat formatter = new SimpleDateFormat("dd MMM yyyy HH:mm:ss z");

formatter.setCalendar(calendar);
formatter.setTimeZone(TimeZone.getTimeZone(timeZone));

String newZealandTime = formatter.format(calendar.getTime());
Run Code Online (Sandbox Code Playgroud)

我希望这是有帮助的!

  • 不好.时区偏移不是恒定的.这取决于实际日期. (3认同)
  • 你如何得到一个实际的日期而不是一个字符串? (2认同)

Bri*_*128 23

与往常一样,我建议您阅读本文关于Java中的日期和时间,以便您了解它.

基本的想法是"在引擎盖下",自纪元以来,一切都以UTC毫秒完成.这意味着如果您在不使用时区的情况下进行操作最简单,除了用户的字符串格式.

因此,我会跳过你建议的大部分步骤.

  1. 设置对象的时间(日期,日历等).
  2. 在格式化程序对象上设置时区.
  3. 从格式化程序返回一个字符串.

或者,您可以使用Joda时间.我听说它是​​一个更直观的日期时间API.


Bas*_*que 15

TL;博士

Instant.ofEpochMilli( 1_317_816_735_000L )
    .atZone( ZoneId.of( "Pacific/Auckland" ) )
    .format( DateTimeFormatter.ofLocalizedDateTime( FormatStyle.MEDIUM ).withLocale( new Locale( "en" , "NZ" ) ) )
Run Code Online (Sandbox Code Playgroud)

…也…

LocalDateTime.parse( "2011-10-06 03:35:05".replace( " " , "T" ) )
    .atZone( ZoneId.of( "Pacific/Auckland" ) )
Run Code Online (Sandbox Code Playgroud)

java.time

问题和大多数答案使用最早版本的Java过时的旧日期时间类.事实证明,这些旧课程很麻烦,令人困惑.避免他们.而是使用java.time类.

ISO 8601

您的输入字符串几乎是标准的ISO 8601格式.只需用中间替换中间的SPACE即可T.

String input = "2011-10-06 03:35:05".replace( " " , "T" );
Run Code Online (Sandbox Code Playgroud)

LocalDateTime

现在解析为LocalDateTime因为输入缺少有关从UTC或时区偏移的任何信息.一个LocalDateTime没有偏移,也没有时区的概念,所以它并不能代表时间轴上的实际的时刻.

LocalDateTime ldt = LocalDateTime.parse( input );
Run Code Online (Sandbox Code Playgroud)

ZoneOffset

您似乎在说,从业务环境中您知道此字符串的意图是表示比UTC早13个小时的时刻.所以我们实例化一个ZoneOffset.

ZoneOffset offset = ZoneOffset.ofHours( 13 ); // 13 hours ahead of UTC, in the far east of the globe.
Run Code Online (Sandbox Code Playgroud)

OffsetDateTime

应用它来获取一个OffsetDateTime对象.这成为时间轴上的实际时刻.

OffsetDateTime odt = ldt.atOffset( offset);
Run Code Online (Sandbox Code Playgroud)

ZoneId

但是你提到了新西兰.所以你有一个特定的时区.时区是与UTC的偏移量加上一组用于处理诸如夏令时(DST)等异常的规则.因此,我们可以指定一个ZoneIdZonedDateTime,而不是一个单纯的偏移.

指定正确的时区名称.切勿使用3-4字母缩写,例如ESTIST因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!).例如,Pacific/Auckland.

ZoneId z = ZoneId.of( "Pacific/Auckland" );
Run Code Online (Sandbox Code Playgroud)

ZonedDateTime

适用ZoneId.

ZonedDateTime zdt = ldt.atZone( z );
Run Code Online (Sandbox Code Playgroud)

您可以在时间轴上的同一时刻轻松调整到另一个区域.

ZoneId zParis = ZoneId.of( "Europe/Paris" );
ZonedDateTime zdtParis = zdt.withZoneSameInstant( zParis );  // Same moment in time, but seen through lens of Paris wall-clock time.
Run Code Online (Sandbox Code Playgroud)

从时代算起

我强烈建议不要将日期时间值作为纪元的计数处理,例如从UTC 1970年开始的毫秒数.但如果必须,请Instant从这样的数字创建一个.

Instant instant = Instant.ofEpochMilli( 1_317_816_735_000L );
Run Code Online (Sandbox Code Playgroud)

然后根据需要分配如上所示的时区,以远离UTC.

ZoneId z = ZoneId.of( "Pacific/Auckland" );
ZonedDateTime zdt = instant.atZone( z );
Run Code Online (Sandbox Code Playgroud)

你的价值1_317_816_735_000L是:

  • 2011-10-05T12:12:15Z (2011年10月5日星期三格林尼治标准时间12:12:15)
  • 2011-10-06T01:12:15+13:00[Pacific/Auckland] (2011年10月6日星期四01:12:15在新西兰奥克兰).

生成字符串

要生成标准ISO 8601格式的字符串,只需调用即可toString.请注意,ZonedDateTime通过在方括号中附加时区名称,明智地扩展了标准格式.

String output = zdt.toString();
Run Code Online (Sandbox Code Playgroud)

对于其他格式,请搜索Stack Overflow for DateTimeFormatterclass.已经多次覆盖.

指定a FormatStyle和a Locale.

Locale l = new Locale( "en" , "NZ" );
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.MEDIUM ).withLocale( l );
String output = zdt.format( f );
Run Code Online (Sandbox Code Playgroud)

请注意,时区与区域设置无关.您可以使用Europe/Paris日语和文化规范Asia/Kolkata显示日期时间,或以葡萄牙语和巴西文化规范显示日期时间.

关于java.time

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

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

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

大部分的java.time功能后移植到Java 6和7 ThreeTen,反向移植,并进一步适应的AndroidThreeTenABP(见如何使用......).

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


小智 7

该解决方案实际上非常简单(纯Java):

System.out.println(" NZ Local Time: 2011-10-06 03:35:05");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime localNZ = LocalDateTime.parse("2011-10-06 03:35:05",formatter);
ZonedDateTime zonedNZ = ZonedDateTime.of(localNZ,ZoneId.of("+13:00"));
LocalDateTime localUTC = zonedNZ.withZoneSameInstant(ZoneId.of("UTC")).toLocalDateTime();
System.out.println("UTC Local Time: "+localUTC.format(formatter));
Run Code Online (Sandbox Code Playgroud)

输出是:

 NZ Local Time: 2011-10-06 03:35:05
UTC Local Time: 2011-10-05 14:35:05
Run Code Online (Sandbox Code Playgroud)


Cra*_*aig 5

看了一下,我不认为Java中的时区是GMT +13。所以我认为您必须使用:

Calendar calendar = Calendar.getInstance();
//OR Calendar.getInstance(TimeZone.getTimeZone("GMT"));

calendar.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY)+13);

Date d = calendar.getTime();
Run Code Online (Sandbox Code Playgroud)

(如果然后将“ GMT”更改为该时区并删除第二行代码)

要么

SimpleDateFormat df = new SimpleDateFormat();
df.setTimeZone(TimeZone.getTimeZone("GMT+13"));
System.out.println(df.format(c.getTime()));
Run Code Online (Sandbox Code Playgroud)

如果要设置特定的时间/日期,则还可以使用:

    calendar.set(Calendar.DATE, 15);
calendar.set(Calendar.MONTH, 3);
calendar.set(Calendar.YEAR, 2011);
calendar.set(Calendar.HOUR_OF_DAY, 13); 
calendar.set(Calendar.MINUTE, 45);
calendar.set(Calendar.SECOND, 00);
Run Code Online (Sandbox Code Playgroud)