我有以下代码
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时间作为返回值。这是正确的,但我想知道这是怎么回事?设备如何知道哪个时区是我给它的日期,以便相应地计算?
答案 0 :(得分:2)
Date
根本没有时区。 SimpleDateFormat
作为解析和格式化的默认值; a Calendar
也是; Date
没有。
鉴于此操作顺序:
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);
我个人建议尽可能使用Joda Time在Java中使用日期/时间工作,请注意。这是一个比Calendar
/ Date
更清晰的API。
答案 1 :(得分:1)
Answer by Jon Skeet是正确的。这是一些经过更新的代码,以使用现代的 java.time 类取代了麻烦的旧式日期时间类。
定义一种格式设置以匹配您的输入。
顺便说一句,您的格式选择不多。相反,我建议使用设计用于交换日期时间值作为文本的标准ISO 8601格式。
您的输入数据或格式设置有缺陷。您使用的小写字母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
用于对生成的表示日期时间对象的文本进行本地化。
要本地化,请指定:
FormatStyle
确定字符串应为多长或缩写。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偏移量指示符的日期时间概念。因此,从技术上讲,在 Joda-Time 及其后继者 java.time 之前的日子里,您的代码是一团糟,无法破解的事情。
我建议花费 no 努力了解Date
和Calendar
的行为。只需继续使用业界领先的日期时间处理框架 java.time 。