在我的网络应用程序中,用户特定活动的日期和时间存储(在数据库中)作为时间戳
Long
,在显示回用户时需要将其转换为正常的日期/时间格式。
(实际上,我的数据库 Cassandra 将写入列时的时间戳存储为一个长值(自 1970 年以来的微秒),我将用它来找出相应用户活动的时间)
我正在使用 JSF 2.0(+ primefaces),我相信它的转换器可能有助于此转换?或者不然我怎样才能最好地实现这些转换?
让我为您提出这个解决方案。因此,在您的托管 bean 中,执行以下操作
public String convertTime(long time){
Date date = new Date(time);
Format format = new SimpleDateFormat("yyyy MM dd HH:mm:ss");
return format.format(date);
}
因此在您的 JSF 页面中,您可以执行此操作(假设
foo
是包含您的 time
的对象)
<h:dataTable value="#{myBean.convertTime(myBean.foo.time)}" />
如果您有多个页面想要使用此方法,您可以将其放入
abstract class
中,并让您的托管 bean 扩展此 abstract class
。
编辑:使用时区返回时间
不幸的是,我认为
SimpleDateFormat
将始终以当地时间格式化时间,因此我们不能再使用SimpleDateFormat
了。所以要显示不同时区的时间,我们可以这样做
public String convertTimeWithTimeZome(long time){
Calendar cal = Calendar.getInstance();
cal.setTimeZone(TimeZone.getTimeZone("UTC"));
cal.setTimeInMillis(time);
return (cal.get(Calendar.YEAR) + " " + (cal.get(Calendar.MONTH) + 1) + " "
+ cal.get(Calendar.DAY_OF_MONTH) + " " + cal.get(Calendar.HOUR_OF_DAY) + ":"
+ cal.get(Calendar.MINUTE));
}
更好的解决方案是利用
JodaTime
。在我看来,这个 API 比 Calendar 好得多(更轻、更快并且提供更多功能)。加上 Calendar.Month
的 January
是 0
,这迫使开发人员将 1
添加到结果中,并且您必须自己格式化时间。使用 JodaTime
,您可以解决所有这些问题。如果我错了请纠正我,但我认为JodaTime
已合并在JDK7
中
ZoneId usersTimeZone = ZoneId.of("Asia/Tashkent");
Locale usersLocale = Locale.forLanguageTag("ga-IE");
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)
.withLocale(usersLocale);
long microsSince1970 = 1_512_345_678_901_234L;
long secondsSince1970 = TimeUnit.MICROSECONDS.toSeconds(microsSince1970);
long remainingMicros = microsSince1970 - TimeUnit.SECONDS.toMicros(secondsSince1970);
ZonedDateTime dateTime = Instant.ofEpochSecond(secondsSince1970,
TimeUnit.MICROSECONDS.toNanos(remainingMicros))
.atZone(usersTimeZone);
String dateTimeInUsersFormat = dateTime.format(formatter);
System.out.println(dateTimeInUsersFormat);
上面的代码片段打印:
2017 年 4 月 05:01:18
“Noll”是盖尔语,表示十二月,所以这应该会让您的用户感到高兴。但塔什干可能很少有讲盖尔语的人,所以请自行指定用户的正确时区和区域。
我认真对待你从数据库中获取微秒的情况。如果第二精度没问题,您可以不使用
remainingMicros
,只使用单参数 Instant.ofEpochSecond()
,这将使代码短几行。由于 Instant
和 ZonedDateTime
确实支持纳秒精度,我发现保持时间戳的完整精度是最正确的。如果您的时间戳以毫秒为单位而不是微秒(通常都是微秒),您可以使用 Instant.ofEpochMilli()
。
7 年前提出这个问题时,使用
Date
、Calendar
和/或 SimpleDateFormat
的答案很好。如今,这些类都已经过时了,我们在现代 Java 日期和时间 API java.time
中拥有更好的东西。
对于大多数用途,我建议您使用内置的本地化格式,就像我在代码中所做的那样。您可以尝试通过
SHORT
、LONG
或 FULL
作为格式样式。您甚至可以使用重载的 ofLocalizedDateTime
方法分别指定日期和时间的格式样式。如果需要特定格式(这是在重复问题中提出的),您可以这样做:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss, dd/MM/uuuu");
使用这个格式化程序,我们得到
05:01:18, 04/12/2017
链接: Oracle 教程:日期时间 解释如何使用
java.time
。
不确定 JSF 是否提供内置功能,但您可以使用
java.sql.Date
的构造函数转换为日期对象:http://download.oracle.com/javase/1.5.0/docs/api/ java/sql/Date.html#Date(长)
然后您应该能够使用 Java SE、Java EE 提供的更高级别的功能来显示和格式化提取的日期。您可以实例化
java.util.Calendar
并显式设置时间: http://download.oracle.com/javase/1.5.0/docs/api/java/util/Calendar.html#setTime(java.util.Date)
编辑:JSF 组件不应该负责转换。您的数据访问层(持久层)应该处理这个问题。换句话说,您的 JSF 组件不应处理
long
类型化属性,而只能处理 Date
或 Calendar
类型化属性。
要显示小时、分钟和秒前面的前导零,请使用以下修改后的代码。这里的技巧是我们将整数转换(或更准确地说格式化)为字符串,以便在适用时显示前导零:
public String convertTimeWithTimeZome(long time) {
Calendar cal = Calendar.getInstance();
cal.setTimeZone(TimeZone.getTimeZone("UTC"));
cal.setTimeInMillis(time);
String curTime = String.format("%02d:%02d:%02d", cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE), cal.get(Calendar.SECOND));
return curTime;
}
结果将类似于:00:01:30
我尝试过这个并为我工作。
Date = (long)(DateTime.Now.Subtract(new DateTime(1970, 1, 1, 0, 0, 0))).TotalSeconds
长时间戳Millis = timestampMicros / 1000; // 将毫秒转换为 LocalDateTime LocalDateTime dateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(timestampMillis), ZoneOffset.UTC); // 使用自定义格式化程序将 LocalDateTime 格式化为字符串 DateTimeFormatter 格式化程序 = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
// Format LocalDateTime to string
System.out.println(dateTime.format(formatter));