0

我正在使用一些遗留代码并且我正在迭代一些值,遗留代码正在使用 sql.timestamp 值检查新一天的开始:

public static final long MILLIS_PER_SECOND = 1000;
public static final long MILLIS_PER_MINUTE = 60 * MILLIS_PER_SECOND;
public static final long MILLIS_PER_HOUR = 60 * MILLIS_PER_MINUTE;
public static final long MILLIS_PER_DAY = 24 * MILLIS_PER_HOUR;

 if (entry.getPeriodEnd().getTime() % TimestampUtils.MILLIS_PER_DAY == 0 || i >= throughputEntries.size()) {

       ...
}

结果永远不会0,所以它只会进入ifi >= throughputEntries.size()

我无法弄清楚他是如何得到0结果的,可能他的数据不同,并且总是以特定的时间段结束,这会产生0

我可以重写代码来检查日期,但想知道他是如何用他的代码实现的。

我不确定这可以用我提供的代码解决,但也许我遗漏了一些东西......

编辑

所以我最终明白了这一点,感谢@t0r0X 和@Leo

我已修改我的代码以使用Joda-Time,如下所示:

 LocalDate newDay = null;
 int count = 0;


public void calcAvg(){

    DateTimeZone zone = DateTimeZone.getDefault();
    LocalDate throughtputDate = entry.getPeriodEnd().toDateTime(zone).toLocalDate();

    if ( this.newDay(throughtputDate) || i >= throughputEntries.size()) {

       ...
    }

}


public boolean newDay(LocalDate date){

    boolean go = false;
    if(count !=0){
        if(date.isAfter(newDay)){

            newDay = date;
            go = true;
        }
    }
    else{
        newDay = date;
        count++;
    }

    return go;
}

可能比我写的方法更干净的检查新日期的方法,但时间不等人。

4

2 回答 2

3

原始代码的作者可能使用了合成的“圆形”数据。也许使用(现在已弃用)java.sql.Timestamp 构造函数......

new Timestamp(116, 1, 25, 0, 0, 0, 0)

或者可能使用(也已弃用)Date 构造函数...

new Timestamp(new Date(116, 1, 25).getTime())

或者他可能已经解析了一些测试数据,例如“2016-01-25”......

看马,没有毫秒!;-)

无论如何,检查“新的一天”取决于你如何定义它。通常你需要一个参考日期,就像之前处理的条目一样。

更新:

第四次查看代码entry.getPeriodEnd().getTime():条目看起来像时间段......所以必须有一种getPeriodBegin()方法......我想需要的检查是验证周期结束是否在另一天而不是周期开始......我对吗?

脏代码(不推荐使用的方法):

Timestamp begin = entry.getPeriodBegin()
Timestamp end = entry.getPeriodEnd()
if (begin.getYear() != end.getYear() || begin.getMonth() != end.getMonth() || begin.getDay() != end.getDay() ....) 

干净的代码:
我的建议:甚至不要从java.util.Calendar 开始(关于 Stackoverflow 的建议)。要么使用来自 Apache Commons Lang 的 DateUtils(也建议在 Stackoverflow 上;评论是相关的),或者,我最喜欢的是,获取JodaTime停止担心(在 Stackoverflow 上也建议;评论是相关的)。我个人一直对 JodaTime 感到满意。

附言

不要忘记(感谢@Leo 对这个问题的评论,我仍然生活在 Java 6-7 的世界中工作:-/ ...):如果使用 Java 8 或更高版本,请选择新的java.time类。

于 2016-01-25T19:28:45.993 回答
1

t0r0X的答案是正确的,但使用了过时的类。

此外,您通常不应该使用 java.sql.* 类来执行业务逻辑。它们旨在用于进出数据库的数据传输,仅此而已。立即将 java.sql.Timestamp/.Date/.Time 转换为 java.time 类型。使用 java.time 类型执行您的业务逻辑。希望有一天,在更新 JDBC 驱动程序以直接处理 java.time 后,java.sql 类型会逐渐消失。

问题和评论不清楚。但我会尝试一下,因为它似乎与按日期累积数字有关。

java.time

Java 8 及更高版本带有出色的java.time框架。请参阅教程。这些新类取代了 java.util.Date/.Calendar 旧的麻烦类。

在这些新类中LocalDate,只有日期值,没有时间和时区。这java.sql.Timestamp是一个日期时间值,而不是仅日期。但我们可以转换为UTCjava.time.Instant时间轴上的某个时刻。然后我们应用时区 ( ) 来获得. 从中我们可以提取一个. 这正是我们作为 a累加数字总和的键所需要的。ZoneIdZonedDateTimeLocalDateLocalDateMap

Instant instant = myJavaSqlTimestamp.toInstant();
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
LocalDate localDate = zdt.toLocalDate();

请注意,时区在这里至关重要。虽然LocalDate不保留时区,但日期仅在时区的上下文中才有意义。对于任何特定时刻,世界各地的日期都不相同。如果未指定,则应用您的 JVM 当前的默认时区。此页面上的其他代码明确要求提供当前默认值。我强烈建议不要在这个问题中使用默认值。JVM 当前的默认时区可以在应用程序运行之前的任何时刻甚至您的应用程序运行时更改!如果按日期汇总数字,则业务逻辑必须考虑某个时区以了解该日期的含义。明确指定该时区。这里我随意选择了America/Montreal

早些时候,您会将MapLocalDate 实例化为正在收集的数字的总和。我假设我们正在处理BigInteger这个演示的数字类型。

Map< LocalDate , BigInteger ) map = new HashMap<>();

我们为遇到的每个LocalDate日期值添加一个条目到该 Map 中。我们假设我们有一个myNumber通过 JDBC 从数据库中获取的 BigInteger。

BigInteger oldTotalForDate = map.get( localDate );
BigInteger newTotalForDate = ( null == oldTotalForDate ) ? myNumber : oldTotalForDate.add( myNumber) ;
if ( null == newTotalForDate ) {  // If we failed to get new sum.
    // TODO: Handle error condition. Perhaps: map.remove(key);
} else {  // Else normal, we have a new total. Store it in map.
    map.put( localDate , newTotalForDate );  // Replaces any old value.
}

Map::merge上面的代码可以通过使用Java 8 及更高版本中的新 Lambda 语法特性的新方法来缩短。

于 2016-01-27T01:34:56.057 回答