我有下面的代码
public Long getEpochTime(String dateToGetItsEpoch) throws ParseException
{
TimeZone timeZone = TimeZone.getTimeZone("UTC");
final String REQUEST_DATE_FORMAT = "dd/MM/yyyy h:m";
DateFormat format = new SimpleDateFormat(REQUEST_DATE_FORMAT);
Date localDate = format.parse(dateToGetItsEpoch);
Calendar cal = Calendar.getInstance(timeZone);
cal.setTime(localDate);
format.setTimeZone(timeZone);
final String utcTime = format.format(cal.getTime());
Date d = cal.getTime();
return d.getTime();
}
如果我将设备的区域设置更改为任意设置,我总是将UTC时间作为返回值。哪一个是正确的,但是我想知道这是怎么发生的?设备如何知道我给它的日期是哪个时区,以便进行相应的计算?
Date
根本没有时区。SimpleDateFormat
作为解析和格式化的默认值;CCD_ 3也这样做;CCD_ 4没有。
给定以下操作序列:
TimeZone timeZone = TimeZone.getTimeZone("UTC");
DateFormat format = new SimpleDateFormat(REQUEST_DATE_FORMAT);
Date localDate = format.parse(dateToGetItsEpoch);
Calendar cal = Calendar.getInstance(timeZone);
cal.setTime(localDate);
format.setTimeZone(timeZone);
final String utcTime = format.format(cal.getTime());
您最初使用设备的默认时区解析字符串,然后以UTC格式格式化字符串。注意,Calendar
部分在这里是不相关的——使用会得到相同的结果
TimeZone timeZone = TimeZone.getTimeZone("UTC");
DateFormat format = new SimpleDateFormat(REQUEST_DATE_FORMAT);
Date date = format.parse(dateToGetItsEpoch);
format.setTimeZone(timeZone);
final String utcTime = format.format(date);
请注意,我个人建议在Java中尽可能使用Joda Time进行日期/时间工作。它是一个比Calendar
/Date
更干净的API。
java.time
Jon Skeet的答案是正确的。这里有一些代码更新为使用现代的java.time类,这些类取代了麻烦的遗留日期-时间类。
格式化模式
定义一个格式模式以匹配您的输入。
顺便说一句,你的格式选择不好。相反,我建议使用标准ISO 8601格式,该格式旨在将日期时间值作为文本进行交换。
12小时与24小时
您的输入数据或格式模式存在缺陷。您使用了小写h
,意思是12小时时钟中一个小时的一到两位数字(而不是24小时时钟,大写H
或HH
)。因此,除非添加一些AM
或PM
的指示符,否则您的输入毫无意义。我认为您在问题代码中错误地忽略了这一点。
Locale locale = Locale.US ;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd/MM/uuuu h:m a" ).withLocale( locale ) ;
LocalDateTime
将此类字符串解析为LocalDateTime
对象,因为它们缺少预期时区或UTC偏移量的指示符。
String input = "23/01/2020 4:5 PM" ;
LocalDateTime ldt = LocalDateTime.parse( input , f ) ;
ldt.toString():2020-01-23T16:05
力矩
我们在上面获得的LocalDateTime
对象不而代表一个时刻,而不是时间线上的一个点。我们的时间是23日下午4点左右。但我们不知道这是东京、图卢兹还是托莱多的下午4点——所有这些时间相隔几个小时。
为了确定一个时刻,我们必须确切地知道预定的时区。然后将该区域应用为ZoneId
以获得ZonedDateTime
。那我们马上就到了。
Locale
不是时区
我的设备的区域设置为任何
Locale
与时区无关。Locale
用于本地化生成的表示日期-时间对象的文本。
要本地化,请指定:
- CCD_ 21来确定字符串的长度或缩写
Locale
确定:- 人类语言,用于日名、月名等的翻译
- 文化规范决定缩写、大写、标点符号、分隔符等问题
示例:
Locale l = Locale.CANADA_FRENCH ; // Or Locale.US, Locale.JAPAN, etc.
DateTimeFormatter f =
DateTimeFormatter
.ofLocalizedDateTime( FormatStyle.FULL )
.withLocale( l )
;
String output = myZonedDateTime.format( f );
你可以让一位来自魁北克的工程师使用Locale.CANADA_FRENCH
进行人类语言和文化规范,但在日本访问时,他使用Asia/Tokyo
时区进行预约。
ZonedDateTime
返回到您的LocalDateTime
对象。如果你确定它代表的是突尼斯挂钟时间中的一个时刻,那么应用Africa/Tunis
时区。
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ;
你问:
设备如何知道我给它的日期是哪个时区,以便进行相应的计算?
你使用了糟糕的日期-时间类,这些类没有考虑到日期-时间的概念,没有时区或UTC偏移的指标。因此,从技术上讲,你的代码是一团糟,是一次黑客攻击,在JodaTime及其继任者java.Time之前的日子里是不可避免的。
我建议花费no的努力来尝试理解CCD_;CCD_ 29。只需继续使用java.time,这是业界领先的日期-时间处理框架。