使用 sql.timestamp 检查新的一天



>我正在使用一些遗留代码,并且正在循环访问一些值,旧代码正在使用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,因此只有在i >= throughputEntries.size()时才会进入if

我无法理解他是如何获得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;
}

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

原始代码的作者可能使用了合成的"圆形"数据。也许使用(现在已弃用的)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类。

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

此外,您通常不应该使用 java.sql.* 类来执行业务逻辑。它们用于传入和传出数据库的数据传输,但仅此而已。立即转换 java.sql.Timestamp/。日期/。时间到 java.time 类型。使用 java.time 类型执行业务逻辑。希望有一天,在JDBC驱动程序更新为直接处理java.time之后,java.sql类型会消失。

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

java.time

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

在这些新类中,LocalDate为仅日期值,没有时间或时区。java.sql.Timestamp是日期时间值,而不是仅日期值。但是我们可以转换为 java.time.Instant ,UTC 时间轴上的一个时刻。然后我们应用一个时区(ZoneId)来得到一个ZonedDateTime。从中我们可以提取一个LocalDate.这个LocalDate正是我们需要的,作为Map积累数字总和的关键。

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.

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

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

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

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.
}

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

最新更新