时区日期转换 [将一个日期对象转换为指定时区的日期对象]

huangapple go评论68阅读模式
英文:

TimeZone Date Conversion [Convert a Date object to a specified timeZone Date Object]

问题

我的方法:
// 初始化日期对象
Date date = new Date();
// 获取时区
ZoneId zoneId = ZoneId.of("Asia/Dubai");

// 创建ZonedDateTime对象
ZonedDateTime zdt = ZonedDateTime.ofInstant(date.toInstant(), zoneId);

// ZonedDateTime的实例
Instant instant = zdt.toInstant();

// 将Instant转换为指定时区
instant.atZone(zoneId);

// 获取本地日期时间对象
LocalDateTime ldt = LocalDateTime.ofInstant(instant, zoneId);

// 将其转换回Date对象
Date dateFinal = java.util.Date.from(Instant.from(ldt.atZone(zoneId)));
英文:
My approach :
// initailize date object
Date date = new Date();
// get time zone
ZoneId zoneId = ZoneId.of("Asia/Dubai");

// create zonedDateTime object
ZonedDateTime zdt = ZonedDateTime.ofInstant(date.toInstant(), zoneId);

// instant of zonedDateTime
Instant instant = zdt.toInstant();

// convert instant to specified zone
instant.atZone(zoneId);

// Get Local Date Time Object
LocalDateTime ldt = LocalDateTime.ofInstant(instant,zoneId);

//Convert it back to Date Object
Date dateFinal = java.util.Date.from(Instant.from(ldt.atZone(zoneId)));

Can anyone help me with conversion of timeZone Date object in Java 8
Date date = Fri Mar 31 16:10:13 IST.
Now I need to convert this Date to any given timeZone Date object

Desired result:

> Date resultDate = Fri Mar 31 14:40:13 GST

Basically here I used (Asia/Dubai) Time Zone

But my result is: 2023-03-31T16:10:13.854+0530. I am getting the result in IST only. It’s not getting converted to (Asia/Dubai).

I have mentioned all the ways I have tried.

答案1

得分: 1

核心概念:java.util.Date 没有时区Date#toString 方法欺骗了你。

如果有一个旧的 java.util.Date 对象,立即转换为 java.time.Instant

Instant instant = myJavaUtilDate.toInstant();

然后应用你所需的时区。

ZonedDateTime zdt = instant.atZone(ZoneId.of("Asia/Dubai"));

仅使用 java.time

你的日期时间处理应该 仅涉及 java.time

日期时间类在该包之外的类现在是遗留的,设计非常糟糕。遗留类在Java 8+中由 java.time 在JSR 310中取代。

你说:

// 初始化日期对象
Date date = new Date();

你是指 java.util.Date 还是 java.sql.Date?两者都是遗留的。

  • 第一个被 java.time.Instant 取代。遗留和现代类都表示与UTC的偏移量为零时分秒的瞬间。
  • 第二个被 java.time.LocalDate 取代。遗留类 假装 表示仅日期,但由于设计缺陷,它实际上包含了一天中的时间和偏移为零的假设。相比之下,现代类真正表示仅日期,不带时间和时区或偏移。

替代使用这段代码:

Instant instant = Instant.now();  // 捕获当前以UTC为基准的瞬间。

你说:

// 获取时区
ZoneId zoneId = ZoneId.of("Asia/Dubai");

很好。ZoneId 是表示时区的现代方式。Asia/DubaiContinent/Region 中是真实时区的正确命名。

你说:

// 创建 ZonedDateTime 对象
ZonedDateTime zdt = ZonedDateTime.ofInstant(date.toInstant(), zoneId);

使用上面看到的我们的 Instant 对象,使用这段代码:

ZonedDateTime zdt = instant.atZone(zoneId);

这里的 instantzdt 代表相同的瞬间,时间轴上的相同点。但后者是通过特定区域的人们使用的挂钟时间查看的。

你说:

// ZonedDateTime 的瞬间
Instant instant = zdt.toInstant();

是的,你可以从 ZonedDateTime 中提取 Instant。但这里的代码是不必要的,因为我们已经实例化了一个 Instant 对象来捕获当前时刻。

你说:

// 将瞬间转换为指定时区
instant.atZone(zoneId);

这里的问题是 Instant 对象,像所有 java.time 对象一样,是不可变的。你无法在创建后更改(“突变”) Instant 对象的内容。那一刻永远被冻结。

此外,调用 Instant#atZone 返回一个全新的 ZonedDateTime 对象。我们在上面的代码中已经看到了这一点。你上面展示的代码忽略了 atZone 返回的新的 ZonedDateTime 对象。

你说:

// 获取本地日期时间对象
LocalDateTime ldt = LocalDateTime.ofInstant(instant, zoneId);

这里有两个问题:

  • 你可以更容易地从上面实例化的 ZonedDateTime 中获得 LocalDateTimeLocalDateTime ldt = zdt.toLocalDateTime();
  • 你可能没有意识到,在创建 LocalDateTime 时,你 丢失了有价值的信息:时区。所以你只剩下一个日期和一天中的时间。但这样的值本质上是模棱两可的。例如,如果今年1月23日中午,我们不知道你是指东京日本的中午,图卢兹法国的中午还是美国俄亥俄州托莱多的中午——这是几个小时的不同时刻。

提示:如果你还没有完全理解日期时间处理,请避免使用 LocalDateTime。在大多数业务情况下,我们通常关心的是一个时刻,时间轴上的特定点。LocalDateTime 不适用于这种情况。

你说:

//将其转换回 Date 对象
Date dateFinal = java.util.Date.from(Instant.from(ldt.atZone(zoneId)));

这里有两个问题:

  • 你可以更容易地写成 java.util.Date.from( instant ),因为我们已经有了一个 Instant。或者,如果我们只有上面看到的 ZonedDateTimejava.util.Date.from( zdt.toInstant() )
  • 通常情况下,你不会在新代码中写这个。仅在必要时与尚未更新为 java.time 的旧代码进行交互时才转换为旧代码。否则,尽量避免使用 Date 类,如同避免使用 CalendarSimpleDateFormat 等。

你的标题问:

>[将 Date 对象转换为指定时区的 Date 对象]

我不明白你的意思。java.util.Date 类表示UTC中的时刻。它没有时区。

(实际上 一个时区被埋在它的代码中,但这个代码几乎是无关紧要的,表示遗留日期时间类中发现的另一种可怕的设计决策。)

你说:

>在 JAVA 8 中的时区 Date 对象是 Fri Mar 31 16:10:13 IST

不要被 java.util.Date#toString 方法愚弄。不幸的是,该方法在生成文本时不断注入JVM的当前默认时区。虽然出于善意,

英文:

tl;dr

Core Concept: java.util.Date does not have a time zone. The Date#toString method lies to you.

If handed a legacy java.util.Date object, immediately convert to java.time.Instant.

Instant instant = myJavaUtilDate.toInstant() ;

Then apply your desired time zone.

ZonedDateTime zdt = instant.atZone( ZoneId.of( "Asia/Dubai" ) ) ;

Use only java.time

Your date-time handling should involve only the java.time classes.

The date-time classes outside that package are now legacy, terribly flawed in poor design. The legacy classes were supplanted by java.time in JSR 310, implemented in Java 8+.

You said:

// initailize date object
Date date = new Date();

Did you mean java.util.Date or java.sql.Date? Both are legacy.

  • The first was replaced by java.time.Instant. Both the legacy and modern classes represent a moment as seen with an offset from UTC of zero hours-minutes-seconds.
  • The second was replaced by java.time.LocalDate. The legacy class pretends to represent a date-only, but because of faulty design it actually contains a time-of-day and an assumption of an offset of zero. In contrast, the modern class truly represents a date-only, without time-of-day, and without time zone or offset.

Instead use this code:

Instant instant = Instant.now() ;  // Capture the current moment as seen in UTC (zero offset).

You said:

// get time zone
ZoneId zoneId = ZoneId.of("Asia/Dubai");

Good. A ZoneId is the modern way to represent a time zone. And Asia/Dubai, in Continent/Region is the correct naming for real time zones.

You said:

// create zonedDateTime object
ZonedDateTime zdt = ZonedDateTime.ofInstant(date.toInstant(), zoneId);

Using our Instant object seen above, use this code:

ZonedDateTime zdt = instant.atZone( zoneId ) ;

Both instant & zdt here represent the same simultaneous moment, the same point on the timeline. But the latter is viewed through the wall-clock time used by people in a particular region.

You said:

// instant of zonedDateTime
Instant instant = zdt.toInstant();

Yes, you can extract an Instant from a ZonedDateTime. But this code in unnecessary here as we already instantiate a Instant object to capture the current moment.

You said:

// convert instant to specified zone
instant.atZone(zoneId);

The problem here is that an Instant object, like all the java.time objects, is immutable. You can alter (“mutate”) the content of an Instant object after its creation. That moment is frozen forever.

Furthermore, calling Instant#atZone returns a fresh new ZonedDateTime object. We saw just that in our code earlier above. Your code shown above ignores the new ZonedDateTime object returned by atZone.

You said:

// Get Local Date Time Object
LocalDateTime ldt = LocalDateTime.ofInstant(instant,zoneId);

Two problem here:

  • You can more easily obtain a LocalDateTime from the ZonedDateTime instantiated above. LocalDateTime ldt = zdt.toLocalDateTime() ;
  • You may not be aware that in creating the LocalDateTime, you are discarding valuable information: the time zone. So you are left with merely a date and a time-of-day. But such a value is inherently ambiguous. For example, if noon on January 23 this year, we do not know if you meant in noon in Tokyo Japan, noon in Toulouse France, or noon in Toledo Ohio US — three very different moments several hours apart.

Tip: If you do not yet fully grok date-time handling, avoid using LocalDateTime. In most business situations, we generally care about a moment, a specific point on the timeline. LocalDateTime does not fit that case.

You said:

//Convert it back to Date Object
Date dateFinal = java.util.Date.from(Instant.from(ldt.atZone(zoneId)));

Two problems here:

  • You can more easily write java.util.Date.from( instant ) as we already have an Instant in hand. Or, if we had just the ZonedDateTime seen above, java.util.Date.from( zdt.toInstant() ).
  • You would usually never write this in new code. Convert to the legacy code only where necessary to interoperate with old code not yet updated to java.time. Otherwise, avoid both Date classes like the plague. Ditto for Calendar, SimpleDateFormat, etc.

Your title asks:

>[Convert a Date object to a specified timeZone Date Object]

I do not understand what you mean. The java.util.Date class represents a moment in UTC. It has no time zone.

(Actually there is a time zone buried with its code, but this code is practically irrelevant, and represents another of those terrible design decisions found in the legacy date-time classes.)

You said:

> timeZone Date object in JAVA 8 Date date = Fri Mar 31 16:10:13 IST

Do not be fooled by the java.util.Date#toString method. That method unfortunately injects the JVM’s current default time zone while generating text. While well-intentioned, this creates the false illusion that Date includes a time zone in its meaning when in fact it is "in UTC" (has an offset from UTC of zero).

huangapple
  • 本文由 发表于 2023年3月31日 19:15:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/75897903.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定