使用sql.timestamp

时间:2016-01-25 19:05:02

标签: java 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所以它只会在if

时进入i >= 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;
}

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

2 个答案:

答案 0 :(得分:3)

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

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

或者可能使用(也已弃用)Date constructor ...

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

或者他可能已经解析了一些测试数据,例如'2016年1月25日' ...

看,马,没有毫米! ; - )

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

更新

第4次查看代码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 (proposal on Stackoverflow)开头。使用DateUtils from Apache Commons Lang(也建议here on Stackoverflow; comments are relevant),或者我最喜欢的是JodaTimestop worring (suggestion also on Stackoverflow; comments are relevant)。我个人总是对JodaTime感到满意。

PS

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

答案 1 :(得分:1)

Answer by t0r0X是正确的,但使用过时的类。

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

问题和意见不明确。但我会采取刺戳,因为它似乎与按日期累积数字有关。

java.time

Java 8及更高版本附带了优秀的java.time框架。见Tutorial。这些新类取代了旧的麻烦的java.util.Date/.Calendar类。

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

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

请注意时区至关重要。虽然LocalDate不保留时区,但日期仅在时区的上下文中有意义。在任何特定时刻,世界各地的日期都不一样。如果未指定,则应用JVM的当前默认时区。此页面上的其他代码明确询问当前默认值。我强烈反对在此问题中使用默认值。 JVM的当前默认时区可以在应用程序运行之前的任何时刻更改,甚至,而您的应用程序运行!如果按日期计算总数,则业务逻辑必须考虑该日期的含义。 Specify that time zone explicitly。在这里,我随意选择了America/Montreal

之前您会将Map的LocalDate实例化为所收集数字的总和。我将假设我们正在处理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方法,可以缩短上面的代码。