开发者

Merge java.util.date with java.sql.Time

开发者 https://www.devze.com 2023-03-04 17:05 出处:网络
I have an extensive DATE-TIME conversion class, but i came across a scenario that i cannot resolve: I have a java.util.date: Tue May 10 00:00:00 BST 2011

I have an extensive DATE-TIME conversion class, but i came across a scenario that i cannot resolve:

I have a java.util.date: Tue May 10 00:00:00 BST 2011

I have a java.sql.time: 03:58:44

I need to create a java.util.date: Tue May 10 03:58:44 BST 2011

The only approach i came up with is:

public static Date getDa开发者_如何学运维te(Date date, Time time) {
    Calendar calendar=Calendar.getInstance();
    calendar.set(date.getYear(), date.getMonth(), date.getDay(), time.getHours(), time.getMinutes(), time.getSeconds());
    return calendar.getTime();
}

Totally deprecated code, and does not work: java.lang.IllegalArgumentException at java.sql.Time.getYear(Unknown Source)

Any ideas?


java.sql.Time is just a wrapper over the java.util.Date. You can use it as if you would add two java.util.Date objects.

For example, set Calendar to java.sql.Time:

calendar.setTime(time);

Now extract the hour/minute/seconds fields, i.e.:

calendar.get(Calendar.HOUR);

Next, set the Calendar to java.util.Date object and add these three fields to its time, i.e.:

calendar.add(Calendar.HOUR, hour);

And get the Date back:

calendar.getTime();


Easiest way would be to just add the milli secs together to create a new date, ala

public static Date getDate(Date date, Time time) {
    return new Date(date.getTime() + time.getTime())
}


vickirk's solution wasn't so bad, but has timezone issues, which results in the one hour less you observed.

I suppose, BST means British Summer Time, which is GMT +0100. Now, java.util.Date and its descendants internally work with numbers of milliseconds since midnight Jan 01, 1970 GMT. The timezone is not taken into account until you stringfy the date/time with toString(). And they use your local timezone for that, which is BST, apparently. That means, what is really stored in these objects, is

java.util.date: Mon May 09 23:00:00 GMT 2011
java.sql.time: 02:58:44 GMT

When you add the internal values (which are retrieved by getTime()) like vickirk suggested, you obtain a date which contains
Tue May 10 01:58:44 GMT 2011, which then results in
Tue May 10 02:58:44 BST 2011 on stringification.

So the explanation for the one hour less is that the timezone offset applies twice, when you stringified the values separately, whereas it applies only once after the addition, because you stringfy only once now. Or, from another point of view, adding the internal value of the point in time 03:58:44 BST is equivalent to adding a time span of 2h 58m 44s.

So to get a time span of 3h 58m 44s encoded in a java.sql.Time, you have to make up for the time zone offset manually. You do that by parsing the time string "00:00:00" with java.sql.Time, which will result in an internal value of -3600000 which is equivalent to 31 Dec 1969 23:00:00 GMT, i.e. one hour before the epoch. This is the negative of the time zone offset.

public static Date mergeDate(Date date, Time time) {
    long tzoffset = -(Time.valueOf("00:00:00").getTime());
    return new Date(date.getTime() + time.getTime() + tzoffset);
}

Of course, all this is a dirty hack, which is necessary because you insist on interpreting the Time's value as a time span, while it really is a point in time.


Instead, you can use this.

   public static Date getDate(Date date, Time time) {
        Calendar calendar=Calendar.getInstance();
        calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
        calendar.setTime(date);
        calendar.add(Calendar.MILLISECOND, (int) time.getTime());
        return calendar.getTime();
    }


Can you do

java.util.Date newDate = new java.util.Date(sqlDate.getTime());


try these

 public static Date getDate(Date date, Time time) {
            Calendar calendar=Calendar.getInstance();
            calendar.setTime(date);
            Calendar calendar1=Calendar.getInstance();
            calendar1.setTime(time);
            calendar.set(Calendar.MINUTE, calendar1.get(Calendar.MINUTE));
            calendar.set(Calendar.SECOND, calendar1.get(Calendar.SECOND));
            calendar.set(Calendar.HOUR_OF_DAY, calendar1.get(Calendar.HOUR_OF_DAY));
            return calendar.getTime();
        }


I recommend that you use java.time, the modern Java date and time API, for your date and time work. If you cannot avoid getting the date as a java.util.Date (a class that doesn’t represent a date) and your time of day as a java.sql.Time, convert both to modern types and combine them from there.

Java 8 and later

    // Time zone to use throughout
    ZoneId zone = ZoneId.systemDefault();
    
    // Initialize values to be used for demonstration
    Instant startOfDay = LocalDate.of(2011, Month.MAY, 10)
            .atStartOfDay(zone)
            .toInstant();
    Date date = Date.from(startOfDay);
    Time time = Time.valueOf(LocalTime.of(3, 58, 44));
    
    // Do work
    LocalTime localTime = time.toLocalTime();
    LocalDateTime combination = date.toInstant()
            .atZone(zone)
            .toLocalDate()
            .atTime(localTime);
    
    // Print result
    System.out.println(combination);

Output:

2011-05-10T03:58:44

Only if you indispensably need a Date, typically for a legacy API that you cannot afford to upgrade to java.time just now, convert back:

    Instant inZone = combination.atZone(zone).toInstant();
    Date oldfashionedDate = Date.from(inZone);
    System.out.println(oldfashionedDate);

In my time zone the output is:

Tue May 10 03:58:44 CEST 2011

Java 6 and 7

For Java 6 and 7 use the backport of java.time, ThreeTen Backport (links at the botton). For the backport we need to use DateTimeUtils for converting to modern types:

    LocalTime localTime = DateTimeUtils.toLocalTime(time);
    LocalDateTime combination = DateTimeUtils.toInstant(date)
            .atZone(zone)
            .toLocalDate()
            .atTime(localTime);

Output is the same as before. Also if you need to convert back to a Date, use DateTimeUtils:

    Instant inZone = combination.atZone(zone).toInstant();
    Date oldfashionedDate = DateTimeUtils.toDate(inZone);

Again output is the same as before.

Links

  • Oracle tutorial: Date Time explaining how to use java.time.
  • Java Specification Request (JSR) 310, where java.time was first described.
  • ThreeTen Backport project, the backport of java.time to Java 6 and 7 (ThreeTen for JSR-310).
  • Java 8+ APIs available through desugaring
  • ThreeTenABP, Android edition of ThreeTen Backport
  • Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
0

精彩评论

暂无评论...
验证码 换一张
取 消