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

发布于 2024-12-08 13:23:37 字数 892 浏览 1 评论 0 原文

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

2011-10-06 03:35:05

我尝试了大约 100 种不同的 DateFormat、TimeZone、Date、GregorianCalendar 等组合来尝试完成这项非常基本的任务。

这段代码做了我想要的当前时间:

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());

但我想要的是设置时间而不是使用当前时间。

我发现每当我尝试像这样设置时间时:

calendar.setTime(new Date(1317816735000L));

使用本地计算机的时区。这是为什么?我知道当“new Date()”返回 UTC+0 时间时,为什么当您以毫秒为单位设置时间时,它不再假定时间是 UTC 时间?

是否可以:

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

I want to convert this GMT time stamp to GMT+13:

2011-10-06 03:35:05

I have tried about 100 different combinations of DateFormat, TimeZone, Date, GregorianCalendar etc. to try to do this VERY basic task.

This code does what I want for the 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());

But what I want is to set the time rather than using the current time.

I found that anytime I try to set the time like this:

calendar.setTime(new Date(1317816735000L));

the local machine's TimeZone is used. Why is that? I know that when "new Date()" returns UTC+0 time so why when you set the Time in milliseconds does it no longer assume the time is in UTC?

Is it possible to:

  1. Set the time on an object (Calendar/Date/TimeStamp)
  2. (Possibly) Set the TimeZone of the initial time stamp (calendar.setTimeZone(...))
  3. Format the time stamp with a new TimeZone (formatter.setTimeZone(...)))
  4. Return a string with new time zone time. (formatter.format(calendar.getTime()))

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(15

深居我梦 2024-12-15 13:23:37

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

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

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()));

For me, the simplest way to do that is:

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

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()));
夜吻♂芭芘 2024-12-15 13:23:37

了解计算机时间的工作原理非常重要。话虽如此,我同意如果创建一个 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());

我希望这样有帮助!

Understanding how computer time works is very important. With that said I agree that if an API is created to help you process computer time like real time then it should work in such a way that allows you to treat it like real time. For the most part this is the case but there are some major oversights which do need attention.

Anyway I digress!! If you have your UTC offset (better to work in UTC than GMT offsets) you can calculate the time in milliseconds and add that to your timestamp. Note that an SQL Timestamp may vary from a Java timestamp as the way the elapse from the epoch is calculated is not always the same - dependant on database technologies and also operating systems.

I would advise you to use System.currentTimeMillis() as your time stamps as these can be processed more consistently in java without worrying about converting SQL Timestamps to java Date objects etc.

To calculate your offset you can try something like this:

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());

I hope this is helpful!

年华零落成诗 2024-12-15 13:23:37

tl;dr

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

…还有…

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

java.time

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

ISO 8601

您的输入字符串几乎采用标准 ISO 8601 格式。只需将中间的空格替换为 T 即可。

String input = "2011-10-06 03:35:05".replace( " " , "T" );

LocalDateTime

现在解析为 < code>LocalDateTime 因为输入缺少有关 UTC 或时区偏移量的任何信息。 LocalDateTime 没有偏移量和时区的概念,因此它代表时间轴上的实际时刻。

LocalDateTime ldt = LocalDateTime.parse( input );

ZoneOffset

您似乎是在说,从业务上下文来看,您知道该字符串的目的是表示比 UTC 早 13 小时的时刻。因此我们实例化一个 ZoneOffset< /a>.

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

OffsetDateTime

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

OffsetDateTime odt = ldt.atOffset( offset);

ZoneId

但是你提到了新西兰。所以您心里有一个特定的时区。时区是相对于 UTC 的偏移量加上一组用于处理夏令时 (DST) 等异常情况的规则。因此,我们可以将 ZoneId 指定为 ZonedDateTime 而不仅仅是偏移量。

指定正确的时区名称。切勿使用 3-4 个字母的缩写,例如 ESTIST,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。例如,太平洋/奥克兰

ZoneId z = ZoneId.of( "Pacific/Auckland" );

ZonedDateTime

应用ZoneId

ZonedDateTime zdt = ldt.atZone( z );

您可以轻松地调整到时间线上同一时刻的另一个区域。

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

从纪元开始计数

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

Instant instant = Instant.ofEpochMilli( 1_317_816_735_000L );

然后根据需要指定一个时区(如上所示)以远离 UTC。

ZoneId z = ZoneId.of( "Pacific/Auckland" );
ZonedDateTime zdt = instant.atZone( z );

您的 1_317_816_735_000L 值为:

  • 2011-10-05T12:12:15Z(2011 年 10 月 5 日星期三 12:12:15 GMT)
  • 2011-10-06T01:12:15+13:00[太平洋/奥克兰](2011 年 10 月 6 日星期四 01:12:15,新西兰奥克兰)。

生成字符串

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

String output = zdt.toString();

对于其他格式,请在 Stack Overflow 中搜索 DateTimeFormatter 类。已经覆盖很多次了。

指定 FormatStyle< /a> 和 Locale

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

请注意,时区与区域设置无关。您可以用日语和日语显示 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 和 Java 6。 ThreeTen-Backport 中的 7 并进一步适应 AndroidThreeTenABP(请参阅如何使用...)。

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是 java.time 未来可能添加的内容的试验场。您可能会在这里找到一些有用的类,例如 IntervalYearWeekYearQuarter 等。

tl;dr

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

…also…

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

java.time

The Question and most Answers use outdated legacy date-time classes from the earliest versions of Java. These old classes have proven to be troublesome and confusing. Avoid them. Instead use the java.time classes.

ISO 8601

Your input string is nearly in standard ISO 8601 format. Just replace the SPACE in the middle with a T.

String input = "2011-10-06 03:35:05".replace( " " , "T" );

LocalDateTime

Now parse as a LocalDateTime because the input lacks any information about offset-from-UTC or time zone. A LocalDateTime has no concept of offset nor time zone, so it does not represent an actual moment on the timeline.

LocalDateTime ldt = LocalDateTime.parse( input );

ZoneOffset

You seem to be saying that from the business context you know the intention of this string is to represent a moment that is 13 hours ahead of UTC. So we instantiate a ZoneOffset.

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

OffsetDateTime

Apply it to get an OffsetDateTime object. This becomes an actual moment on the timeline.

OffsetDateTime odt = ldt.atOffset( offset);

ZoneId

But then you mention New Zealand. So you had a specific time zone in mind. A time zone is an offset-from-UTC plus a set of rules for handling anomalies such as Daylight Saving Time (DST). So we can specify a ZoneId to a ZonedDateTime rather than a mere offset.

Specify a proper time zone name. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!). For example, Pacific/Auckland.

ZoneId z = ZoneId.of( "Pacific/Auckland" );

ZonedDateTime

Apply the ZoneId.

ZonedDateTime zdt = ldt.atZone( z );

You can easily adjust into another zone for the very same moment on the timeline.

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

Count from epoch

I strongly recommend against handling date-time values as a count from epoch, such as milliseconds from the start of 1970 UTC. But if you must, create a Instant from such a number.

Instant instant = Instant.ofEpochMilli( 1_317_816_735_000L );

Then assign a time zone as seen above, if desired, to move away from UTC.

ZoneId z = ZoneId.of( "Pacific/Auckland" );
ZonedDateTime zdt = instant.atZone( z );

Your value of 1_317_816_735_000L is:

  • 2011-10-05T12:12:15Z (Wed, 05 Oct 2011 12:12:15 GMT)
  • 2011-10-06T01:12:15+13:00[Pacific/Auckland] (Thursday October 06, 2011 01:12:15 in Auckland New Zealand).

Generate strings

To generate a string in standard ISO 8601 format, simply call toString. Note that ZonedDateTime wisely extends the standard format by appending the name of the time zone in square brackets.

String output = zdt.toString();

For other formats, search Stack Overflow for DateTimeFormatter class. Already covered many times.

Specify a FormatStyle and a Locale.

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

Note that time zone has nothing to do with locale. You can have a Europe/Paris date-time displayed in Japanese language & cultural norms, or a Asia/Kolkata date-time displayed in Portuguese language and Brazil cultural norms.

About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old date-time classes such as java.util.Date, .Calendar, & java.text.SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to java.time.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations.

Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP (see How to use…).

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

稍尽春風 2024-12-15 13:23:37

与往常一样,我建议您阅读这篇关于 Java 中的日期和时间的文章,以便您理解它。

基本思想是,“在幕后”,一切都是自纪元以来的 UTC 毫秒内完成的。这意味着,如果您完全不使用时区进行操作,则最简单,但用户的字符串格式除外。

因此,我会跳过您建议的大部分步骤。

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

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

As always, I recommend reading this article about date and time in Java so that you understand it.

The basic idea is that 'under the hood' everything is done in UTC milliseconds since the epoch. This means it is easiest if you operate without using time zones at all, with the exception of String formatting for the user.

Therefore I would skip most of the steps you have suggested.

  1. Set the time on an object (Date, Calendar etc).
  2. Set the time zone on a formatter object.
  3. Return a String from the formatter.

Alternatively, you can use Joda time. I have heard it is a much more intuitive datetime API.

恍梦境° 2024-12-15 13:23:37

解决方案实际上非常简单(纯粹、简单的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));

输出是:

 NZ Local Time: 2011-10-06 03:35:05
UTC Local Time: 2011-10-05 14:35:05

The solution is actually quite simple (pure, simple 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));

OUTPUT IS:

 NZ Local Time: 2011-10-06 03:35:05
UTC Local Time: 2011-10-05 14:35:05
乖乖公主 2024-12-15 13:23:37

看了一下,我认为 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();

如果有,则将“GMT”更改为该时区并删除第二行代码)

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

如果您想设置特定时间/日期,您还可以使用:

    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);

Had a look about and I don't think theres a timezone in Java that is GMT + 13. So I think you have to use:

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();

(If there is then change "GMT" to that Timezone and remove the 2nd line of code)

OR

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

If you want to set a specific time/date you can also use:

    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);
流年里的时光 2024-12-15 13:23:37

我已经尝试过这段代码

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();
        }

并得到了这个结果

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

I have try this code

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();
        }

and getting this result

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
旧夏天 2024-12-15 13:23:37

我们可以通过使用偏移值来处理这个问题

 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();
}

测试代码片段:

 System.out.println(new Date().getTime())
 System.out.println(convertDateTimeZone(new Date().getTime(), TimeZone
                .getDefault().getID(), "EST"));

输出:
1387353270742
1387335270742

We can handle this by using offset value

 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();
}

Test Code snippet:

 System.out.println(new Date().getTime())
 System.out.println(convertDateTimeZone(new Date().getTime(), TimeZone
                .getDefault().getID(), "EST"));

Output:
1387353270742
1387335270742

心的憧憬 2024-12-15 13:23:37

我想提供现代的答案。

您不应该真正想要将日期和时间从一个 GMT 偏移量的字符串转换为不同 GMT 偏移量和不同格式的字符串。相反,在您的程序中保留一个瞬间(时间点)作为正确的日期时间对象。仅当您需要提供字符串输出时,才将对象格式化为所需的字符串。

java.time

解析输入

    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();

对于大多数用途来说,Instant 是存储时间点的不错选择。如果您需要明确表明日期和时间来自 GMT,请改用 OffsetDateTime

转换、格式化和打印输出

    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);

这打印了:

2011 年 10 月 6 日 16:35:05 GMT+13:00

我指定了太平洋/奥克兰时区,而不是您提到的偏移量 +13:00。我知道您想要新西兰时间,太平洋/奥克兰更好地告诉读者这一点。时区还考虑夏令时 (DST),因此您无需在自己的代码中考虑这一点(对于大多数用途)。

由于 Oct 是英语,因此最好为格式化程序提供显式区域设置。 GMT 也可能已本地化,但我认为它只是在所有语言环境中打印 GMT

格式模式字符串中的 OOOO 是打印偏移量的一种方法,这可能比打印从 z 获得的时区缩写更好,因为时区缩写是常常含糊其辞。如果您需要 NZDT(新西兰夏令时),只需将 z 放在那里即可。

您的问题

我将回答您与 java.time 中的现代类相关的编号问题。

可以:

  1. 设置对象的时间

不,现代类是不可变的。您需要从一开始就创建一个具有所需日期和时间的对象(这有很多优点,包括线程安全)。

  • (可能)设置初始时间戳的TimeZone
  • 我在代码中使用的 atZone 方法返回具有指定时区的 ZonedDateTime 。其他日期时间类也有类似的方法,有时称为 atZoneSameInstant 或其他名称。

  • 使用新时区格式化时间戳
  • 将 java.time 转换为新时区并格式化是两个不同的步骤,如图所示。

  • 返回包含新时区时间的字符串。
  • 是的,转换为如图所示的所需时区和如图所示的格式。

    我发现每当我尝试像这样设置时间时:

    calendar.setTime(new Date(1317816735000L));
    

    使用本地计算机的时区。这是为什么?

    这不是你想的那样,它很好地展示了旧类的几个(许多)设计问题。

    • Date 没有时区。仅当您打印它时,它的 toString 方法才会获取您的本地时区并使用它来呈现字符串。 new Date() 也是如此。在过去的 25 年里,这种行为让很多很多程序员感到困惑。
    • 日历有一个时区。当您执行 calendar.setTime(new Date(1317816735000L)); 时,它不会改变。

    链接

    Oracle 教程:日期时间 解释如何使用 java.time。

    I should like to provide the modern answer.

    You shouldn’t really want to convert a date and time from a string at one GMT offset to a string at a different GMT offset and with in a different format. Rather in your program keep an instant (a point in time) as a proper date-time object. Only when you need to give string output, format your object into the desired string.

    java.time

    Parsing input

        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();
    

    For most purposes Instant is a good choice for storing a point in time. If you needed to make it explicit that the date and time came from GMT, use an OffsetDateTime instead.

    Converting, formatting and printing output

        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);
    

    This printed:

    06 Oct 2011 16:35:05 GMT+13:00

    I specified time zone Pacific/Auckland rather than the offset you mentioned, +13:00. I understood that you wanted New Zealand time, and Pacific/Auckland better tells the reader this. The time zone also takes summer time (DST) into account so you don’t need to take this into account in your own code (for most purposes).

    Since Oct is in English, it’s a good idea to give the formatter an explicit locale. GMT might be localized too, but I think that it just prints GMT in all locales.

    OOOO in the format patterns string is one way of printing the offset, which may be a better idea than printing the time zone abbreviation you would get from z since time zone abbreviations are often ambiguous. If you want NZDT (for New Zealand Daylight Time), just put z there instead.

    Your questions

    I will answer your numbered questions in relation to the modern classes in java.time.

    Is possible to:

    1. Set the time on an object

    No, the modern classes are immutable. You need to create an object that has the desired date and time from the outset (this has a number of advantages including thread safety).

    1. (Possibly) Set the TimeZone of the initial time stamp

    The atZone method that I use in the code returns a ZonedDateTime with the specified time zone. Other date-time classes have a similar method, sometimes called atZoneSameInstant or other names.

    1. Format the time stamp with a new TimeZone

    With java.time converting to a new time zone and formatting are two distinct steps as shown.

    1. Return a string with new time zone time.

    Yes, convert to the desired time zone as shown and format as shown.

    I found that anytime I try to set the time like this:

    calendar.setTime(new Date(1317816735000L));
    

    the local machine's TimeZone is used. Why is that?

    It’s not the way you think, which goes nicely to show just a couple of the (many) design problems with the old classes.

    • A Date hasn’t got a time zone. Only when you print it, its toString method grabs your local time zone and uses it for rendering the string. This is true for new Date() too. This behaviour has confused many, many programmers over the last 25 years.
    • A Calender has got a time zone. It doesn’t change when you do calendar.setTime(new Date(1317816735000L));.

    Link

    Oracle tutorial: Date Time explaining how to use java.time.

    り繁华旳梦境 2024-12-15 13:23:37

    显示所有时区的日期和时间

    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);
    }
    

    display date and time for all timezones

    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);
    }
    
    梨涡 2024-12-15 13:23:37

    一种快速方法是:

    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

    A quick way is :

    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);
    

    Output

    NEW DATE: 2015-07-02T16:51:46

    不知在何时 2024-12-15 13:23:37

    您的方法无需任何修改即可工作。

    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()));
    

    Your approach works without any modification.

    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()));
    
    冰葑 2024-12-15 13:23:37

    Joda-Time

    java.util.Date/Calendar 类很混乱,应该避免。

    更新:Joda-Time 项目处于维护模式。该团队建议迁移到 java.time 类。

    这是使用 Joda-Time 2.3 库的答案。很容易。

    如示例代码中所述,我建议您尽可能使用命名时区,以便您的编程可以处理夏令时(夏令时)和其他异常情况。

    如果您在字符串中间放置了一个 T 而不是空格,则可以跳过前两行代码,使用格式化程序来解析字符串。 DateTime 构造函数可以采用 < 中的字符串href="https://en.wikipedia.org/wiki/ISO_8601" rel="nofollow">ISO 8601 格式。

    // © 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 );
    

    转储这些值...

    System.out.println( "dateTimeInUTC: " + dateTimeInUTC );
    System.out.println( "thirteenDateTime: " + thirteenDateTime );
    System.out.println( "tongatapuDateTime: " + tongatapuDateTime );
    

    运行时...

    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
    

    Joda-Time

    The java.util.Date/Calendar classes are a mess and should be avoided.

    Update: The Joda-Time project is in maintenance mode. The team advises migration to the java.time classes.

    Here's your answer using the Joda-Time 2.3 library. Very easy.

    As noted in the example code, I suggest you use named time zones wherever possible so that your programming can handle Daylight Saving Time (DST) and other anomalies.

    If you had placed a T in the middle of your string instead of a space, you could skip the first two lines of code, dealing with a formatter to parse the string. The DateTime constructor can take a string in ISO 8601 format.

    // © 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 );
    

    Dump those values…

    System.out.println( "dateTimeInUTC: " + dateTimeInUTC );
    System.out.println( "thirteenDateTime: " + thirteenDateTime );
    System.out.println( "tongatapuDateTime: " + tongatapuDateTime );
    

    When run…

    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
    
    若言繁花未落 2024-12-15 13:23:37
    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;
    }
    
    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;
    }
    
    迎风吟唱 2024-12-15 13:23:37

    查找具有两个不同时区

    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

    days = 117
    minutes = 40
    hours = 13
    

    To find duration or time interval with two different time zone

    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
    

    output
    period = P117DT13H40M

    days = 117
    minutes = 40
    hours = 13
    
    ~没有更多了~
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文