使用 JodaTime 将 UTC 转换为本地时间(以毫秒为单位)

2024-04-28

我正在尝试使用 Jodatime 显示特定时间段内的交易。

我们的服务器要求开始日期和结束日期采用 UTC(这可能是显而易见的)。因此,围绕这些的任何业务逻辑都使用 DateTime 对象,并将时区设置为DateTimeZone.UTC, e.g.

mStartDate = DateTime.now(UTC).withTimeAtStartOfDay();

这很有效,除非涉及到display我不知道如何为本地(系统默认)时区增加它的时间。理想情况下我想使用DateUtils 格式化日期范围 https://developer.android.com/reference/android/text/format/DateUtils.html#formatDateRange(android.content.Context,%20java.util.Formatter,%20long,%20long,%20int,%20java.lang.String)函数传入两个本地时间戳。但是getMillis()函数似乎没有考虑本地偏移:

我也尝试过这个:

mTimePeriodTitle.setText(DateUtils.formatDateRange(mContext, f, mStartDate.getMillis(),
    mEndDate.getMillis(), DateUtils.FORMAT_SHOW_TIME,
    TimeZone.getDefault().getID()).toString());

但这没有任何区别。所以我的问题是如何获得具有 2 个 UTC 时间戳的格式良好的本地日期范围?


If your DateTime是 UTC 并且您想将其转换为另一个时区,您可以使用withZone方法进行转换。

对于下面的示例,我的默认时区是America/Sao_Paulo(你可以使用检查你的DateTimeZone.getDefault()):

// create today's date in UTC
DateTime mStartDate = DateTime.now(DateTimeZone.UTC).withTimeAtStartOfDay();
// date/time in UTC
System.out.println(mStartDate); // 2017-06-13T00:00:00.000Z
// date/time in my default timezone (America/Sao_Paulo)
System.out.println(mStartDate.withZone(DateTimeZone.getDefault())); // 2017-06-12T21:00:00.000-03:00

输出是:

2017-06-13T00:00:00.000Z
2017-06-12T21:00:00.000-03:00

请注意,withZone方法正确地将日期和时间转换为我的时区(在America/Sao_Paulo当前偏移量是UTC-03:00),因此进行了相应调整。

如果您只想获取时间(小时/分钟/秒),您可以使用toLocalTime() method:

System.out.println(mStartDate.withZone(DateTimeZone.getDefault()).toLocalTime()); // 21:00:00.000

输出是:

21:00:00.000

如果您想要其他格式(例如,不打印秒分数的 3 位数字),您可以使用DateTimeFormatter。好处是你可以在格式化程序中设置时区,所以你不需要转换DateTime:

// create formatter for hour/minute/second, set it with my default timezone
DateTimeFormatter fmt = DateTimeFormat.forPattern("HH:mm:ss").withZone(DateTimeZone.getDefault());
System.out.println(fmt.print(mStartDate)); // 21:00:00

输出是:

21:00:00

要获得您的范围,您可以将上述方法之一与您的DateTime's (mStartDate and mEndDate),并使用DateTimeFormatter更改为您需要的任何格式。


PS:我认为你在使用时缺少什么getMillis()两个日期时间(UTC 和默认时区)都代表同一个瞬间。您只是将这一时刻转换为当地时间,但毫秒是相同的(想想,现在,此时此刻,世界上的每个人都在同一时刻(相同的毫秒),但他们的当地时间可能不同取决于他们在哪里)。因此,在转换 UTC 时DateTime到另一个时区,我们只是找到该时区的当地时间,它对应于相同的毫秒。

您可以使用以下命令检查这一点getMillis()两个对象上的方法:

System.out.println(mStartDate.getMillis()); // 1497312000000
System.out.println(mStartDate.withZone(DateTimeZone.getDefault()).getMillis()); // 1497312000000

请注意,即使我将对象转换为另一个时区,毫秒仍保持不变(1497312000000)。这是因为两者都代表同一时刻,我只是将它们移动到各自当地时间不同的另一个时区。


Java 新的日期/时间 API

Joda-Time 它已停产并被新的 API 取代,因此我不建议用它开始一个新项目。如果您的情况如此,您可以考虑使用新的日期/时间 API,但如果您有一个使用 Joda 的大型代码库或者现在不想迁移它,您可以考虑其余的答案。

无论如何,即使在乔达的网站 http://www.joda.org/joda-time它说:“请注意,Joda-Time 被认为是一个很大程度上“完成”的项目。没有计划进行重大增强。如果使用 Java SE 8,请迁移到 java.time (JSR-310)。”.*

如果您正在使用Java 8,考虑使用新的 java.time API https://docs.oracle.com/javase/tutorial/datetime/。更容易,与旧 API 相比,漏洞较少且不易出错 https://stackoverflow.com/questions/1969442/whats-wrong-with-java-date-time-api。我不确定它是否已适用于所有 Android 版本(但请参阅下面的替代方案)。

如果您正在使用Java ,您可以使用三十向后移植 http://www.threeten.org/threetenbp/,Java 8 新日期/时间类的一个很好的向后移植。而对于Android,有一种方法可以使用它,通过三十ABP https://github.com/JakeWharton/ThreeTenABP(更多关于如何使用它here https://stackoverflow.com/a/38922755/7605325).

下面的代码适用于两者。 唯一的区别是包名称(在 Java 8 中是java.time在 ThreeTen Backport(或 Android 的 ThreeTenABP)中是org.threeten.bp),但是类和方法names是相同的。

要获取当天开始时的当前日期(UTC),您可以执行以下操作:

// UTC's today at start of the day
ZonedDateTime utc = LocalDate.now(ZoneOffset.UTC).atStartOfDay(ZoneOffset.UTC);
System.out.println(utc); // 2017-06-13T00:00Z

首先我做了LocalDate.now(ZoneOffset.UTC)查找当前本地 UTC 日期。如果我只使用LocalDate.now(),它将获取我的默认时区中的当前日期,这不是我们想要的(它可能与 UTC 不同,具体取决于您所在的位置和时间以及默认时区是什么)。

然后我用了atStartOfDay(ZoneOffset.UTC)以 UTC 开始新的一天。我知道使用 UTC 两次听起来多余,但 API 允许我们在此方法中使用任何时区,并且 IMO 它明确说明了我们想要的时区(如果日期位于夏令时更改的时区,则一天的开始可能不是午夜 - 时区参数是为了保证设置正确的值)。

输出是:

2017-06-13T00:00Z

要转换为我的默认时区,我可以使用ZoneId.systemDefault(),在我的例子中返回America/Sao_Paulo。要转换它并仅获取当地时间部分,只需执行以下操作:

System.out.println(utc.withZoneSameInstant(ZoneId.systemDefault()).toLocalTime()); // 21:00

输出是:

21:00

如果你想改变它,你也可以使用格式化程序:

// formatter for localtime (hour/minute/second)
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("HH:mm:ss");
System.out.println(fmt.format(utc.withZoneSameInstant(ZoneId.systemDefault()))); // 21:00:00

输出是:

21:00:00

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 JodaTime 将 UTC 转换为本地时间(以毫秒为单位) 的相关文章

随机推荐