UTC使用JodaTime以毫秒为单位的当地时间

Dan*_*son 3 java datetime android jodatime datetime-conversion

我试图使用Jodatime显示特定时间段内的交易.

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

mStartDate = DateTime.now(UTC).withTimeAtStartOfDay();
Run Code Online (Sandbox Code Playgroud)

除了显示我不知道如何为本地(系统默认)时区增加它的时间之外,这很有效.理想情况下,我想使用DateUtils formatDateRange函数传递两个本地时间戳.但该getMillis()功能似乎没有考虑到本地偏移:

时间戳返回相同的毫秒时间

我也试过这个:

mTimePeriodTitle.setText(DateUtils.formatDateRange(mContext, f, mStartDate.getMillis(),
    mEndDate.getMillis(), DateUtils.FORMAT_SHOW_TIME,
    TimeZone.getDefault().getID()).toString());
Run Code Online (Sandbox Code Playgroud)

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

小智 6

如果您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
Run Code Online (Sandbox Code Playgroud)

输出是:

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

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

如果您想获得时间(小时/分钟/秒),您可以使用toLocalTime()方法:

System.out.println(mStartDate.withZone(DateTimeZone.getDefault()).toLocalTime()); // 21:00:00.000
Run Code Online (Sandbox Code Playgroud)

输出是:

21:00:00.000

如果你想要另一种格式(例如,不打印秒数的3位数),你可以使用a 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
Run Code Online (Sandbox Code Playgroud)

输出是:

21:00:00

要获得您的范围,您可以使用上述方法之一与您DateTime的(mStartDatemEndDate),并使用DateTimeFormatter更改为您需要的任何格式.


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

您可以getMillis()在两个对象上使用该方法检查:

System.out.println(mStartDate.getMillis()); // 1497312000000
System.out.println(mStartDate.withZone(DateTimeZone.getDefault()).getMillis()); // 1497312000000
Run Code Online (Sandbox Code Playgroud)

请注意,即使我将对象转换为另一个时区,millis仍然是相同的(1497312000000).那是因为两者都代表同一时刻,我只是将它们移动到另一个时区,其中各自的当地时间不同.


Java新的日期/时间API

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

无论如何,即使在joda的网站上它也说:"请注意,Joda-Time被认为是一个很大程度上已经完成的项目.没有计划进行重大改进.如果使用Java SE 8,请迁移到java.time(JSR-310). " *.

如果您使用的是Java 8,请考虑使用新的java.time API.与旧的API相比,它更容易,更少出错并且更不容易出错.我不确定它是否已经可用于所有Android版本(但请参阅下面的替代方案).

如果您使用Java <= 7,则可以使用ThreeTen Backport,这是Java 8的新日期/时间类的一个很好的后端.对于Android,有一种方法可以使用它,使用ThreeTenABP(更多关于如何在这里使用它).

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

要以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
Run Code Online (Sandbox Code Playgroud)

首先,我做了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
Run Code Online (Sandbox Code Playgroud)

输出是:

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
Run Code Online (Sandbox Code Playgroud)

输出是:

21:00:00