使用Java 8时间API获取第一个和最后一个时间(毫秒)

使用Java 8时间API获取第一个和最后一个时间(毫秒),java,java-8,jfreechart,java-time,Java,Java 8,Jfreechart,Java Time,我正在将我的时间计算从自我实现的代码转换为Java8时间API 我需要从java.time.Year或java.time.Month类中获得以毫秒为单位的开始和结束时间,我计划稍后在JFreeChart的另一层中使用它 我需要JFreeChart的org.jfree.data.time.RegularTimePeriod类中的getFirst毫秒()和getLast毫秒()之类的函数 我已经实现了类似的代码- public static long getStartTimeInMillis(jav

我正在将我的时间计算从自我实现的代码转换为Java8时间API

我需要从
java.time.Year
java.time.Month
类中获得以毫秒为单位的开始和结束时间,我计划稍后在JFreeChart的另一层中使用它

我需要JFreeChart的
org.jfree.data.time.RegularTimePeriod
类中的
getFirst毫秒()
getLast毫秒()
之类的函数

我已经实现了类似的代码-

public static long getStartTimeInMillis(java.time.Year year, java.time.Month month) {       
    if (year != null && month != null) {
        return LocalDate.of(year.getValue(), month, 1).with(TemporalAdjusters.firstDayOfMonth()).
                atStartOfDay().atZone(TimeZone.getDefault().toZoneId()).toInstant().toEpochMilli();
    } else if (year != null) {
        return LocalDate.of(year.getValue(), java.time.Month.JANUARY, 1).with(TemporalAdjusters.firstDayOfMonth()).
                atStartOfDay().atZone(TimeZone.getDefault().toZoneId()).toInstant().toEpochMilli();
    }       
    return 0;
}

public static long getEndTimeInMillis(java.time.Year year, java.time.Month month) {
    if (year != null && month != null) {
        return LocalDate.of(year.getValue(), month, 1).with(TemporalAdjusters.lastDayOfMonth()).
                atTime(OffsetTime.MAX).toLocalDateTime().atZone(TimeZone.getDefault().toZoneId()).toInstant().toEpochMilli();
    } else if (year != null) {
        return  LocalDate.of(year.getValue(), java.time.Month.DECEMBER, 1).with(TemporalAdjusters.lastDayOfMonth()).
                atTime(OffsetTime.MAX).toLocalDateTime().atZone(TimeZone.getDefault().toZoneId()).toInstant().toEpochMilli();
    }       
    return 0;
}

但在我看来,这真的很复杂。有没有更好/更短的方法来获取这些值?

我会这样重构

public static long getStartTimeInMillis(java.time.Year year, Optional<Month> monthOpt) {
    Month month = monthOpt.orElse(Month.JANUARY);

    if (year != null) {
        return LocalDate.of(year.getValue(), month, 1)
                .with(TemporalAdjusters.firstDayOfMonth())
                .atStartOfDay()
                .atZone(TimeZone.getDefault().toZoneId())
                .toInstant()
                .toEpochMilli();
    }

    return 0;
}
public static long getStartTimeInMillis(java.time.Year,可选monthOpt){
月份=蒙霍普特奥莱尔斯(一月);
如果(年份!=null){
返回LocalDate.of(year.getValue(),month,1)
.with(临时调整器.firstDayOfMonth())
.atStartOfDay()
.atZone(TimeZone.getDefault().toZoneId())
.toInstant()
.toEpochMilli();
}
返回0;
}
YearMonth
是的,有一个稍微好一点的方法。使用java.time中包含的类

另外,将调用链分解为单独的语句,以使其更可读,更易于跟踪/调试。信任JVM代表您进行优化;只有在使代码更可读、更容易理解的地方才使用调用链接

通过
时区
获取JVM的当前默认时区是不必要的。相反,打电话

设置一些输入值

// Inputs
Year year = Year.of ( 2015 );
Month month = Month.DECEMBER;
方法的核心部分

// Code for your method.
YearMonth yearMonth = year.atMonth ( month ); // Instantiate a YearMonth from a Year and a Month.
LocalDate localDate = yearMonth.atDay ( 1 ); // First day of month.
ZoneId zoneId = ZoneId.systemDefault (); // Or… ZoneId.of("America/Montreal");
ZonedDateTime zdt = localDate.atStartOfDay ( zoneId );
long millis = zdt.toInstant ().toEpochMilli ();
转储到控制台

System.out.println ( "year: " + year + " | month: " + month + " | yearMonth: " + yearMonth + " | zoneId:" + zoneId + " | zdt: " + zdt + " | millis: " + millis );
年份:2015年|月份:12月|年月份:2015-12 |地区ID:美国/洛杉矶| zdt:2015-12-01T00:00-08:00[美国/洛杉矶]|米利斯:1448956800000


更好的是,将
YearMonth
实例传递给您的方法,而不是一对
Year
Month
对象。如果您的其他业务逻辑正在使用
+
对,请改用
年-月
——这就是它的用途。

除了在给定
年和信任系统默认时区时返回
0
的可疑做法之外,您可以按如下方式重写您的方法:

public static long getStartTimeInMillis(java.time.Year year, java.time.Month month) {
    if (year == null) {
        return 0;
    }

    if (month == null) {
        month = Month.JANUARY;
    }

    return year.atMonth(month)
            .atDay(1)
            .atStartOfDay()
            .atZone(ZoneId.systemDefault())
            .toInstant()
            .toEpochMilli();

}

public static long getEndTimeInMillis(java.time.Year year, java.time.Month month) {
    if (year == null) {
        return 0;
    }

    if (month == null) {
        month = Month.JANUARY;
    }

    return year.atMonth(month)
            .atEndOfMonth()
            .atTime(LocalTime.MAX)
            .atZone(ZoneId.systemDefault())
            .toInstant()
            .toEpochMilli();
};
要扩展,如果年份为
null
,则最好只抛出
NullPointerException
。如果您通过了一个空年份,那么上游代码中可能有一个bug。返回一个没有意义的0只会将bug推到更远的地方,使其更难追踪。这一原则被称为“快速失效”


依赖系统默认时区对于重要的生产代码来说是一个坏主意,因为它往往会导致问题,因为服务器的配置可能不可预测(例如GMT),或者当地理分布的服务器位于不同的时区时,您可能会遇到问题。仔细考虑“我计算这些时间的时区是什么?”这一问题可以避免头疼。这确实很有帮助。谢谢您的回答。好的,我将把我的时区更改为“ZoneId.systemDefault()”。但在你看来,什么是更好的回报率实践呢-62135773200000以毫秒为单位的默认时间戳??我在答案中添加了一个澄清。看看这有没有道理,我会考虑的。谢谢。你为什么不能改用JFreeChart子类呢?@MenoHochschild正如我提到的,图表的创建是在另一个层中进行的,我不想导入包,只在time API中使用JFreeChart类。包含JFreeChart的部分是一个大型框架中的插件。所以我想创建实用程序方法,每个开发人员都可以使用,即使他们不需要创建图表,但只想进行时间计算。好的,我知道JFreeChart要求每个设计需要毫秒,因此您的转换实用程序可以用于特定目的(在图表层),但为什么用户需要将应用程序的其他部分转换为毫秒?这里最合适的单位是月,而不是毫秒。@menohochshild我们有很多遗留代码,它们取决于不同的时间类,如java.util.Calendar、java.util.Date、java.sql.Date和java.sql.Timestamp。是的,这是一个混乱,但我不想重构一切。我认为MyLISCs可以是一个很好的基础,如果其他开发人员需要一些转换。如果在非Frice图表层中的应用程序设计需要整数量和单位枚举/标识符的组合,就值得考虑。但好吧,重构的成本也要考虑在内。