Convert Date/Time for given Timezone - java
我想将此GMT时间戳转换为GMT + 13:
1 | 2011-10-06 03:35:05 |
我尝试过大约100种不同的DateFormat,TimeZone,Date,GregorianCalendar等组合来尝试做这个非常基本的任务。
这段代码完成了我对CURRENT TIME的要求:
1 2 3 4 5 6 | 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()); |
但我想要的是设定时间而不是使用当前时间。
我发现任何时候我都尝试设置这样的时间:
1 |
使用本地机器的TimeZone。这是为什么?我知道当"new Date()"返回UTC + 0时,为什么当你设置Time以毫秒为单位时,它不再假设时间是UTC?
有可能:
在此先感谢您的帮助:D
对我来说,最简单的方法是:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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())); |
了解计算机时间的工作原理非常重要。有了这个说我同意,如果创建一个API来帮助您像实时一样处理计算机时间,那么它应该以允许您像实时一样对待它的方式工作。在大多数情况下都是这种情况,但有一些重要的疏忽需要注意。
无论如何我离题!如果您有UTC偏移(最好在UTC中工作而不是GMT偏移),您可以计算时间(以毫秒为单位)并将其添加到时间戳。请注意,SQL时间戳可能与Java时间戳不同,因为计算时间的过程并不总是相同的 - 这取决于数据库技术和操作系统。
我建议您使用System.currentTimeMillis()作为时间戳,因为这些可以在java中更一致地处理,而不必担心将SQL时间戳转换为Java Date对象等。
要计算您的偏移量,您可以尝试这样的事情:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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()); |
我希望这是有帮助的!
与往常一样,我建议您阅读本文关于Java中的日期和时间,以便您了解它。
基本的想法是"在引擎盖下",自纪元以来,一切都以UTC毫秒完成。这意味着如果您在不使用时区的情况下进行操作最简单,除了用户的字符串格式。
因此,我会跳过你建议的大部分步骤。
或者,您可以使用Joda时间。我听说它是??一个更直观的日期时间API。
TL;博士
1 2 3 | Instant.ofEpochMilli( 1_317_816_735_000L ) .atZone( ZoneId.of("Pacific/Auckland" ) ) .format( DateTimeFormatter.ofLocalizedDateTime( FormatStyle.MEDIUM ).withLocale( new Locale("en" ,"NZ" ) ) ) |
…也…
1 2 | LocalDateTime.parse("2011-10-06 03:35:05".replace("" ,"T" ) ) .atZone( ZoneId.of("Pacific/Auckland" ) ) |
java.time
问题和大多数答案使用最早版本的Java过时的旧日期时间类。事实证明,这些旧课程很麻烦,令人困惑。避免他们。而是使用java.time类。
ISO 8601
您的输入字符串几乎是标准的ISO 8601格式。只需用
1 |
现在解析为
1 | LocalDateTime ldt = LocalDateTime.parse( input ); |
您似乎在说,从业务环境中您知道此字符串的意图是表示比UTC早13个小时的时刻。所以我们实例化一个
1 | ZoneOffset offset = ZoneOffset.ofHours( 13 ); // 13 hours ahead of UTC, in the far east of the globe. |
<5233>
应用它来获取
1 | OffsetDateTime odt = ldt.atOffset( offset); |
但是你提到了新西兰。所以你有一个特定的时区。时区是与UTC的偏移量加上一组用于处理诸如夏令时(DST)等异常的规则。所以我们可以指定
指定正确的时区名称。切勿使用3-4字母缩写,例如
1 | ZoneId z = ZoneId.of("Pacific/Auckland" ); |
应用
1 | ZonedDateTime zdt = ldt.atZone( z ); |
您可以在时间轴上的同一时刻轻松调整到另一个区域。
1 2 | ZoneId zParis = ZoneId.of("Europe/Paris" ); ZonedDateTime zdtParis = zdt.withZoneSameInstant( zParis ); // Same moment in time, but seen through lens of Paris wall-clock time. |
从时代算起
我强烈建议不要将日期时间值作为纪元的计数处理,例如从UTC 1970年开始的毫秒数。但如果必须,请从这样的数字创建
1 | Instant instant = Instant.ofEpochMilli( 1_317_816_735_000L ); |
然后根据需要分配如上所示的时区,以远离UTC。
1 2 | ZoneId z = ZoneId.of("Pacific/Auckland" ); ZonedDateTime zdt = instant.atZone( z ); |
您的
-
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格式的字符串,只需调用
1 |
对于其他格式,请搜索
指定
1 2 3 |
请注意,时区与区域设置无关。您可以使用日语和日语显示
关于java.time
java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧日期时间类,例如
现在处于维护模式的Joda-Time项目建议迁移到java.time。
要了解更多信息,请参阅Oracle教程。并搜索Stack Overflow以获取许多示例和解释。
许多java.time功能都被反向移植到Java 6&amp; 7在ThreeTen-Backport中,并在ThreeTenABP中进一步适应Android(请参阅如何使用...)。
ThreeTen-Extra项目使用其他类扩展了java.time。该项目是未来可能添加到java.time的试验场。您可以在这里找到一些有用的类,例如
解决方案实际上非常简单(纯粹,简单的Java):
1 2 3 4 5 6 | 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)); |
输出是:
看一下,我不认为Java中的时区是GMT + 13.所以我认为你必须使用:
1 2 3 4 5 6 |
(如果有更改"GMT"到该时区并删除第二行代码)
要么
1 2 3 | SimpleDateFormat df = new SimpleDateFormat(); df.setTimeZone(TimeZone.getTimeZone("GMT+13")); System.out.println(df.format(c.getTime())); |
如果您想设置特定的时间/日期,您还可以使用:
1 2 3 4 5 6 |
乔达时间
java.util.Date/Calendar类是一团糟,应该避免。
更新:Joda-Time项目处于维护模式。该团队建议迁移到java.time类。
以下是使用Joda-Time 2.3库的答案。很容易。
如示例代码中所述,我建议您尽可能使用命名时区,以便您的编程可以处理夏令时(DST)和其他异常。
如果你在字符串的中间放置了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // ? 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so. // import org.joda.time.*; // import org.joda.time.format.*; // Parse string as a date-time in UTC (no time zone offset). DateTimeFormatter formatter = org.joda.time.format.DateTimeFormat.forPattern("yyyy-MM-dd' 'HH:mm:ss" ); DateTime dateTimeInUTC = formatter.withZoneUTC().parseDateTime("2011-10-06 03:35:05" ); // Adjust for 13 hour offset from UTC/GMT. DateTimeZone offsetThirteen = DateTimeZone.forOffsetHours( 13 ); DateTime thirteenDateTime = dateTimeInUTC.toDateTime( offsetThirteen ); // Hard-coded offsets should be avoided. Better to use a desired time zone for handling Daylight Saving Time (DST) and other anomalies. // Time Zone list… http://joda-time.sourceforge.net/timezones.html DateTimeZone timeZoneTongatapu = DateTimeZone.forID("Pacific/Tongatapu" ); DateTime tongatapuDateTime = dateTimeInUTC.toDateTime( timeZoneTongatapu ); |
转储这些价值......
1 2 3 |
跑的时候......
1 2 3 | dateTimeInUTC: 2011-10-06T03:35:05.000Z thirteenDateTime: 2011-10-06T16:35:05.000+13:00 tongatapuDateTime: 2011-10-06T16:35:05.000+13:00 |
我们可以使用偏移值来处理这个问题
1 2 3 4 5 6 7 8 9 10 11 12 13 | public static long convertDateTimeZone(long lngDate, String fromTimeZone, String toTimeZone){ TimeZone toTZ = TimeZone.getTimeZone(toTimeZone); Calendar toCal = Calendar.getInstance(toTZ); TimeZone fromTZ = TimeZone.getTimeZone(fromTimeZone); Calendar fromCal = Calendar.getInstance(fromTZ); fromCal.setTimeInMillis(lngDate); toCal.setTimeInMillis(fromCal.getTimeInMillis() + toTZ.getOffset(fromCal.getTimeInMillis()) - TimeZone.getDefault().getOffset(fromCal.getTimeInMillis())); return toCal.getTimeInMillis(); } |
测试代码段:
1 2 3 |
输出:
1387353270742
1387335270742
我试过这段代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | try{ SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss Z"); Date datetime = new Date(); System.out.println("date"+sdf.format(datetime)); sdf.setTimeZone(TimeZone.getTimeZone("GMT")); System.out.println("GMT"+ sdf.format(datetime)); sdf.setTimeZone(TimeZone.getTimeZone("GMT+13")); System.out.println("GMT+13"+ sdf.format(datetime)); sdf.setTimeZone(TimeZone.getTimeZone("UTC")); System.out.println("utc"+sdf.format(datetime)); 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()); System.out.println("using calendar"+newZealandTime); }catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } |
得到这个结果
1 2 3 4 5 | date 06-10-2011 10:40:05 +0530 GMT 06-10-2011 05:10:05 +0000 // here getting 5:10:05 GMT+13 06-10-2011 06:10:05 +1300 // here getting 6:10:05 utc 06-10-2011 05:10:05 +0000 using calendar 06 Oct 2011 18:10:05 GMT+13:00 |
一个快速的方法是:
1 2 3 4 5 6 7 8 | String dateText ="Thu, 02 Jul 2015 21:51:46"; long hours = -5; // time difference between places DateTimeFormatter formatter = DateTimeFormatter.ofPattern(E, dd MMM yyyy HH:mm:ss, Locale.ENGLISH); LocalDateTime date = LocalDateTime.parse(dateText, formatter); date = date.with(date.plusHours(hours)); System.out.println("NEW DATE:"+date); |
产量
新日期:2015-07-02T16:51:46
显示所有时区的日期和时间
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import java.util.Calendar; import java.util.TimeZone; import java.text.DateFormat; import java.text.SimpleDateFormat; static final String ISO8601 ="yyyy-MM-dd'T'HH:mm:ssZ"; DateFormat dateFormat = new SimpleDateFormat(ISO8601); Calendar c = Calendar.getInstance(); String formattedTime; for (String availableID : TimeZone.getAvailableIDs()) { dateFormat.setTimeZone(TimeZone.getTimeZone(availableID)); formattedTime = dateFormat.format(c.getTime()); System.out.println(formattedTime +"" + availableID); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | public Timestamp convertLocalTimeToServerDatetime(String dt,String timezone){ String clientDnT = dt ;//"2017-06-01 07:20:00"; try{ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date date = sdf.parse(clientDnT); TimeZone tz = TimeZone.getTimeZone(timezone.trim()); // get time zone of user sdf.setTimeZone(tz); // Convert to servertime zone SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); TimeZone tzInAmerica = TimeZone.getDefault(); sdf1.setTimeZone(tzInAmerica); // assign date to date String serverDate = sdf1.format(date); // Convert to servertime zone to Timestamp Date date2 = sdf.parse(serverDate); Timestamp tsm = new Timestamp(date2.getTime()); return tsm; } catch(Exception e){ System.err.println(e); } return null; } |
查找具有两个不同时区的持续时间或时间间隔
1 2 3 4 5 6 7 8 9 10 | import org.joda.time.{DateTime, Period, PeriodType} val s1 ="2019-06-13T05:50:00-07:00" val s2 ="2019-10-09T11:30:00+09:00" val period = new Period(DateTime.parse(s1), DateTime.parse(s2), PeriodType dayTime()) period.getDays period.getMinutes period.getHours |
产量
周期= P117DT13H40M
1 2 3 | days = 117 minutes = 40 hours = 13 |
我想提供现代的答案。
您不应该真正想要将日期和时间从一个GMT偏移处的字符串转换为不同GMT偏移处的字符串并使用不同的格式。而是在你的程序中保持一个即时(一个时间点)作为一个正确的日期时间对象。只有在需要提供字符串输出时,才能将对象格式化为所需的字符串。
java.time
解析输入
1 2 3 4 5 6 7 8 9 10 | DateTimeFormatter formatter = new DateTimeFormatterBuilder() .append(DateTimeFormatter.ISO_LOCAL_DATE) .appendLiteral(' ') .append(DateTimeFormatter.ISO_LOCAL_TIME) .toFormatter(); String dateTimeString ="2011-10-06 03:35:05"; Instant instant = LocalDateTime.parse(dateTimeString, formatter) .atOffset(ZoneOffset.UTC) .toInstant(); |
对于大多数用途,
转换,格式化和打印输出
1 2 3 4 5 6 7 8 | ZoneId desiredZone = ZoneId.of("Pacific/Auckland"); Locale desiredeLocale = Locale.forLanguageTag("en-NZ"); DateTimeFormatter desiredFormatter = DateTimeFormatter.ofPattern( "dd MMM uuuu HH:mm:ss OOOO", desiredeLocale); ZonedDateTime desiredDateTime = instant.atZone(desiredZone); String result = desiredDateTime.format(desiredFormatter); System.out.println(result); |
这印刷:
06 Oct 2011 16:35:05 GMT+13:00
我指定时区Pacific / Auckland而不是你提到的偏移量+13:00。我知道你想要新西兰时间,太平洋/奥克兰更好地告诉读者这一点。时区也考虑夏令时(DST),因此您不需要在自己的代码中考虑这一点(大多数情况下)。
由于
格式模式字符串中的
你的问题
我将回答有关java.time中现代类的编号问题。
Is possible to:
Set the time on an object
不,现代课程是不可改变的。您需要从一开始就创建一个具有所需日期和时间的对象(这具有许多优点,包括线程安全性)。
(Possibly) Set the TimeZone of the initial time stamp
我在代码中使用的
Format the time stamp with a new TimeZone
使用java.time转换为新的时区,格式化是两个不同的步骤,如图所示。
Return a string with new time zone time.
是的,如图所示转换为所需的时区,格式如图所示。
I found that anytime I try to set the time like this:
1the local machine's TimeZone is used. Why is that?
这不是你想象的方式,这很好地展示了旧类的几个(很多)设计问题。
-
A
Date 没有时区。只有当你打印它时,它的toString 方法才会抓取你的本地时区并用它来渲染字符串。对于new Date() 也是如此。在过去的25年中,这种行为使许多程序员感到困惑。 -
A
Calender 有一个时区。当你执行calendar.setTime(new Date(1317816735000L)); 时它不会改变。
链接
Oracle教程:Date Time解释如何使用java.time。
我们可以从给定日期获得UTC / GMT时间戳。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | /** * Get the time stamp in GMT/UTC by passing the valid time (dd-MM-yyyy HH:mm:ss) */ public static long getGMTTimeStampFromDate(String datetime) { long timeStamp = 0; Date localTime = new Date(); String format ="dd-MM-yyyy HH:mm:ss"; SimpleDateFormat sdfLocalFormat = new SimpleDateFormat(format); sdfLocalFormat.setTimeZone(TimeZone.getDefault()); try { localTime = (Date) sdfLocalFormat.parse(datetime); Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"), Locale.getDefault()); TimeZone tz = cal.getTimeZone(); cal.setTime(localTime); timeStamp = (localTime.getTime()/1000); Log.d("GMT TimeStamp:"," Date TimegmtTime:" + datetime +", GMT TimeStamp :" + localTime.getTime()); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return timeStamp; } |
它将根据传递的日期返回UTC时间。
-
我们可以像UTC时间戳一样反向到当前日期和时间(反之亦然)
1
2
3
4
5
6
7
8
9
10
11
12
13public static String getLocalTimeFromGMT(long gmtTimeStamp) {
try{
Calendar calendar = Calendar.getInstance();
TimeZone tz = TimeZone.getDefault();
calendar.setTimeInMillis(gmtTimeStamp * 1000);
// calendar.add(Calendar.MILLISECOND, tz.getOffset(calendar.getTimeInMillis()));
SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
Date currenTimeZone = (Date) calendar.getTime();
return sdf.format(currenTimeZone);
}catch (Exception e) {
}
return"";
}
我希望这会有助于其他人。谢谢!!
您的方法无需任何修改即可运行
1 2 3 4 5 6 7 8 9 | Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT")); // Timestamp for 2011-10-06 03:35:05 GMT calendar.setTime(new Date(1317872105000L)); DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z"); formatter.setTimeZone(TimeZone.getTimeZone("GMT+13")); // Prints 2011-10-06 16:35:05 GMT+13:00 System.out.println(formatter.format(calendar.getTime())); |