简体   繁体   English

将时间戳转换为特定时区的日期时间

[英]Convert timestamp to Date time for a particular timezone

I want to convert a timestamp (which is in GMT) to a local date and time .我想将时间戳(which is in GMT)转换为local date and time

This is what I have implemented so far, but it is giving me wrong month这是我迄今为止实施的,但它给了我错误的月份

Timestamp stp = new Timestamp(1640812878000L);
Calendar convertTimestamp = convertTimeStamp(stp,"America/Phoenix");
System.out.println(convertTimestamp.getTime());
    

public static Calendar convertTimeStamp( Timestamp p_gmtTime, String p_timeZone) throws Exception {
        SimpleDateFormat sdf = new SimpleDateFormat("MMM dd, yyyy HH:MM:SS a", Locale.ENGLISH);
        DateFormat formatter = DateFormat.getDateTimeInstance();
        if (p_timeZone != null) {
            formatter.setTimeZone(TimeZone.getTimeZone(p_timeZone));
        } else {
            formatter.setTimeZone(TimeZone.getTimeZone("GMT"));
        }

        String gmt_time = formatter.format(p_gmtTime);
        Calendar cal = Calendar.getInstance();
        cal.setTime(sdf.parse(gmt_time));
        return cal;
    }

Any help would be appreciated.任何帮助,将不胜感激。

You cannot convert a timestamp to another timezone, cause timestamps are always GMT, they are a given moment in the line of time in the universe.您不能将时间戳转换为另一个时区,因为时间戳始终是 GMT,它们是宇宙中时间线上的给定时刻。

We humans are used to local time on our planet, so a timestamp can be formatted to be more human readable, and in that context it is converted to a local timezone.我们人类习惯于地球上的当地时间,因此可以将时间戳格式化为更易于阅读,并在这种情况下将其转换为当地时区。

Using legacy java.util.* packages, this is done as follows:使用旧版 java.util.* 包,按如下方式完成:

DateFormat tzFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
tzFormat.setTimeZone(TimeZone.getTimeZone("CET")); // Use whatever timezone
System.out.println(tzFormat.format(date));

If you need to make "math" over the timestamp on local timezone (like, tomorrow at 8:00 local timezone), then the situation is more complex.如果您需要对本地时区的时间戳进行“数学运算”(例如,明天本地时区的 8:00),那么情况会更加复杂。

To do this you can resort to a number of hacks (like parsing or modifying the string obtained with the method above), or use the new Java date & time classes that have a specific class to deal with date and time in local time zones:为此,您可以诉诸一些技巧(例如解析或修改通过上述方法获得的字符串),或使用具有特定 class 的新 Java 日期和时间类来处理本地时区的日期和时间:

Instant timestamp = Instant.ofEpochMilli(inputValue);
ZonedDateTime romeTime = timestamp.atZone(ZoneId.of("Europe/Rome"));

Note how this second example uses "Europe/Rome" and not generically "CET".请注意第二个示例如何使用“Europe/Rome”而不是一般的“CET”。 This is very important if you're planning to deal with timezones where DST is used, cause the DST change day (or if they use DST or not) may change from country to country even if they are in the same timezone.如果您计划处理使用 DST 的时区,这一点非常重要,因为 DST 更改日期(或者是否使用 DST)可能会因国家/地区而异,即使它们位于同一时区。

tl;dr tl;博士

Instant
.ofEpochMilli(                       // Parse a count of milliseconds since 1970-01-01T00:00Z.
    1_640_812_878_000L
)                                    // Returns a `Instant` object.
.atZone(                             // Adjust from UTC to a time zone. Same moment, same point on the timeline, different wall-clock time.
    ZoneId.of( "America/Phoenix" ) 
)                                    // Returns a `ZonedDateTime` object.
.format(                             // Generat text representing the date-time value kept within that `ZonedDateTime` object.
    DateTimeFormatter
    .ofLocalizedDateTime( FormatStyle.MEDIUM )
    .withLocale( Locale.US ) 
)                                    // Returns a `String` object.

See this code run live at IdeOne.com .请参阅在 IdeOne.com 上实时运行的代码

Dec 29, 2021, 2:21:18 PM 2021 年 12 月 29 日下午 2:21:18

Details细节

You are using terrible old date-time classes that were years ago supplanted by the modern java.time classes defined in JSR 310. Never use Timestamp , Calendar , Date , SimpleDateFormat , etc.您正在使用多年前被 JSR 310 中定义的现代java.time类取代的糟糕的旧日期时间类。切勿使用TimestampCalendarDateSimpleDateFormat等。

Use the Instant class to represent a moment as seen in UTC, with an offset of zero hours-minutes-seconds.使用Instant class 来表示以 UTC 表示的时刻,偏移量为零时分秒。

long millisecondsSinceBeginningOf1970InUtc = 1_640_812_878_000L ;
Instant instant = Instant.ofEpochMilli( millisecondsSinceBeginningOf1970InUtc ) ;

Specify the time zone in which you are interested.指定您感兴趣的时区。

ZoneID z = ZoneId.of( "Africa/Tunis" ) ;

Adjust from offset of zero to that time zone to produce a ZonedDateTime object.从零偏移量调整到该时区以生成ZonedDateTime object。

ZonedDateTime zdt = instant.atZone( z ) ;

Generate text representing that moment by automatically localizing.通过自动本地化生成代表那一刻的文本。 Use a Locale to specify the human language to use in translation as well as a culture to use in deciding abbreviation, capitalization, order of elements, and so on.使用Locale来指定在翻译中使用的人类语言以及在决定缩写、大小写、元素顺序等时使用的文化。

Locale locale = Locale.JAPAN ; // Or Locale.US, Locale.ITALY, etc.
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.LONG ).withLocale( locale ) ;
String output = zdt.format( f ) ;

All of this has been addressed many times on Stack Overflow.所有这些都已在 Stack Overflow 上多次解决。 Search to learn more.搜索以了解更多信息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM