使用可选部分格式化日期
Formatting a Date with optional parts
我正在寻找一个干净的解决方案来格式化带有可选部分的 Date 对象。我的日期对象可以是时间戳值、仅时间值或仅日期值。
预期输出
我想像这样显示日期值:
如果日期的 ms value 小于 (86400*1000) 那么这意味着该值是一个真正的时间值。如果是这样显示:
HH:mm:ss.SSS
如果日期的值恰好在午夜,则表示它是一个仅限日期的值。如果是这样显示:
yyyy-MM-dd
否则显示如下:
yyyy-MM-dd HH:mm:ss.SSS
解约束
不幸的是,我正在使用 Date
作为输入。无法更改。我只对 formatting/rendering 感兴趣,对解析不感兴趣。外部图书馆在我的组织中很难销售。
出于格式化的目的,首先转换为新的 Java 8 date/time 对象之一当然是可以接受的,如果这样可以使解决方案更简单。
平台:Java 8 SE
而不是 java.util.Date
使用 java.time
包中适当的 class。这意味着您可以为您的 LocalDate
、LocalTime
或 LocalDateTime
显式地使用单独的方法,并且它使代码更清晰。
现在,如果您被 java.util.Date
困住了并且对此无能为力,您应该使用 getTime()
方法(您已经知道)在各种 SimpleDateFormat
每种输出类型的实现。
您可以尝试导入和使用 java.sql.Time
类似于:
import java.sql.Time;
public class Example {
public static void main(String[] args) {
Time ex = new Time( Date.getTime() ); //param: long
System.out.println(ex.toString()); // prints 00:05:28
}
}
编辑:Joe C 解决这个问题的方法可以说比我的实现要好。
我认为您需要多个 SimpleDateFormat 对象。您的代码可能如下所示:
SimpleDateFormat timeOnlySdf = new SimpleDateFormat( "HH:mm:ss.SSS");
SimpleDateFormat dateOnlySdf = new SimpleDateFormat( "yyyy-MM-dd");
SimpleDateFormat dateAndTimeSdf = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss.SSS");
Date epochPlusOne = new Date( 86400 * 1000);
Calendar cal = Calendar.getInstance();
cal.setTime( myDate);
if( myDate.before( epochPlusOne))
{
System.out.println( timeOnlySdf.format( myDate));
}
else if( cal.get( Calendar.HOUR) == 0 &&
cal.get( Calendar.MINUTE) == 0 &&
cal.get( Calendar.SECOND) == 0 &&
cal.get( Calendar.MILLISECOND) == 0)
{
System.out.println( dateOnlySdf.format( myDate));
}
else
{
System.out.println( dateAndTimeSdf.format( myDate));
}
第一步
将Date
转换为Java 8等价结构:
private static TemporalAccessor toJava8Time(Date date) {
Instant instant = date.toInstant();
if (instant.isBefore(Instant.ofEpochSecond(86400))) {
return instant.atZone(ZoneId.systemDefault()).toLocalTime();
} else if (instant.equals(instant.truncatedTo(ChronoUnit.HOURS))) {
return instant.atZone(ZoneId.systemDefault()).toLocalDate();
} else {
return instant.atZone(ZoneId.systemDefault()).toLocalDateTime();
}
}
第二步
创建足够通用的格式化程序以根据需要对 LocalTime
、LocalDate
和 LocalDateTime
进行字符串化:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("[yyyy-MM-dd] [HH:mm:ss]");
用法
Date time = new Date(39733000L); // 1970-01-01T12:02:13
Date date = new Date(1462399200000L); // 2016-05-05T00:00:00
Date dateTime = new Date(1462442533000L); // 2016-05-05T12:02:13
Stream.of(time, date, dateTime)
.map(d -> toJava8Time(d))
.map(t -> formatter.format(t).trim())
.forEach(System.out::println);
//Outputs "12:02:13", "2016-05-05", "2016-05-05 12:02:13"
注意:我必须调用 trim()
,否则时间将以 space 开始。
我正在寻找一个干净的解决方案来格式化带有可选部分的 Date 对象。我的日期对象可以是时间戳值、仅时间值或仅日期值。
预期输出
我想像这样显示日期值:
如果日期的 ms value 小于 (86400*1000) 那么这意味着该值是一个真正的时间值。如果是这样显示:
HH:mm:ss.SSS
如果日期的值恰好在午夜,则表示它是一个仅限日期的值。如果是这样显示:
yyyy-MM-dd
否则显示如下:
yyyy-MM-dd HH:mm:ss.SSS
解约束
不幸的是,我正在使用 Date
作为输入。无法更改。我只对 formatting/rendering 感兴趣,对解析不感兴趣。外部图书馆在我的组织中很难销售。
出于格式化的目的,首先转换为新的 Java 8 date/time 对象之一当然是可以接受的,如果这样可以使解决方案更简单。
平台:Java 8 SE
而不是 java.util.Date
使用 java.time
包中适当的 class。这意味着您可以为您的 LocalDate
、LocalTime
或 LocalDateTime
显式地使用单独的方法,并且它使代码更清晰。
现在,如果您被 java.util.Date
困住了并且对此无能为力,您应该使用 getTime()
方法(您已经知道)在各种 SimpleDateFormat
每种输出类型的实现。
您可以尝试导入和使用 java.sql.Time
类似于:
import java.sql.Time;
public class Example {
public static void main(String[] args) {
Time ex = new Time( Date.getTime() ); //param: long
System.out.println(ex.toString()); // prints 00:05:28
}
}
编辑:Joe C 解决这个问题的方法可以说比我的实现要好。
我认为您需要多个 SimpleDateFormat 对象。您的代码可能如下所示:
SimpleDateFormat timeOnlySdf = new SimpleDateFormat( "HH:mm:ss.SSS");
SimpleDateFormat dateOnlySdf = new SimpleDateFormat( "yyyy-MM-dd");
SimpleDateFormat dateAndTimeSdf = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss.SSS");
Date epochPlusOne = new Date( 86400 * 1000);
Calendar cal = Calendar.getInstance();
cal.setTime( myDate);
if( myDate.before( epochPlusOne))
{
System.out.println( timeOnlySdf.format( myDate));
}
else if( cal.get( Calendar.HOUR) == 0 &&
cal.get( Calendar.MINUTE) == 0 &&
cal.get( Calendar.SECOND) == 0 &&
cal.get( Calendar.MILLISECOND) == 0)
{
System.out.println( dateOnlySdf.format( myDate));
}
else
{
System.out.println( dateAndTimeSdf.format( myDate));
}
第一步
将Date
转换为Java 8等价结构:
private static TemporalAccessor toJava8Time(Date date) {
Instant instant = date.toInstant();
if (instant.isBefore(Instant.ofEpochSecond(86400))) {
return instant.atZone(ZoneId.systemDefault()).toLocalTime();
} else if (instant.equals(instant.truncatedTo(ChronoUnit.HOURS))) {
return instant.atZone(ZoneId.systemDefault()).toLocalDate();
} else {
return instant.atZone(ZoneId.systemDefault()).toLocalDateTime();
}
}
第二步
创建足够通用的格式化程序以根据需要对 LocalTime
、LocalDate
和 LocalDateTime
进行字符串化:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("[yyyy-MM-dd] [HH:mm:ss]");
用法
Date time = new Date(39733000L); // 1970-01-01T12:02:13
Date date = new Date(1462399200000L); // 2016-05-05T00:00:00
Date dateTime = new Date(1462442533000L); // 2016-05-05T12:02:13
Stream.of(time, date, dateTime)
.map(d -> toJava8Time(d))
.map(t -> formatter.format(t).trim())
.forEach(System.out::println);
//Outputs "12:02:13", "2016-05-05", "2016-05-05 12:02:13"
注意:我必须调用 trim()
,否则时间将以 space 开始。