How to compare Calendar's time to java.sql.Tim

2019-08-30 18:47发布

问题:

I want to know whether the Time values of a Calendar object equal the value of a java.sql.Time object.

E.g

Calendar c; //c.getTime().toString() == "Sat Jan 07 09:00:00 GMT 2012"
Time t;     //d.toString() == "09:00:00";

I tried

t.equals(c.getTime())

But because the Calendar has Date information the expression is false.

What would be the best way the compare the two?

Edit:
The Time object is retrieve though Hibernate and come with no date information.

The Calendar object is create by

Calendar c= Calendar.getInstance();
c.set(Calendar.HOUR_OF_DAY, 9);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);

回答1:

The way you use is perfectly fine. The goal is unclear, though. Why do you want c to be equal to d?

Additionally, there's no way to have d.toString() == "09:00:00"Date always have, well, the date included.

What's more important, though, is that Date has no timezone information (well, it used to have, but you're discouraged to touch this part of Date), so you cannot tell 09:00 UTC from 10:00 BST—that is, unless you specify the timezone. You can get the timezone from Calendar c, and it sort of explains what you need to do:

  1. Create a Calendar from your date
  2. Copy timezone from the calendar you already use
  3. Compare the Calendar fields which are of interest for you. I suppose that will be hour, minute, second, and, perhaps, millisecond.

Update: now that you've mentioned it's actually java.sql.Time, I'm worried. The problem is,

  • SQL servers usually store time as a structure containing hours, minutes, seconds, etc. That is, there's an implied timezone (the SQL Server timezone)
  • java.sql.Time stores time as milliseconds since "zero epoch" value of January 1, 1970. The date part is usually stripped to January 1, 1970 — but this class does not contain timezone information. (Well, again, it sort of does, but it's deprecated.)
  • Calendar has an explicitly set timezone

What it means in practice is, that the time from the server gets converted into milliseconds using system default timezone, then you read this value and compare it with a Calendar with its own timezone.

If it sounds confusing and fragile, that's because it is. So basically you have three timezones:

  1. SQL Server TZ
  2. JVM's default TZ
  3. Calendar's TZ

All three must be the same so that any comparison would make any sense.



回答2:

You can use Date, Calendar, GregorianCalendar,SimpleDateFormat` etc classes to deal with date-time in Java. Let's see some examples.

SimpleDateFormat dayFormat = new SimpleDateFormat("D");
int _currentDay = Integer.parseInt(dayFormat.format(new Date(System.currentTimeMillis())));

SimpleDateFormat monthFormat = new SimpleDateFormat("M");
int _currentMonth = Integer.parseInt(monthFormat.format(new Date(System.currentTimeMillis())));

SimpleDateFormat yearFormat = new SimpleDateFormat("yyyy");
int _currentYear = Integer.parseInt(yearFormat.format(new Date(System.currentTimeMillis())));

System.out.println(_currentDay+"/"+_currentMonth+"/"+_currentYear);

Would display the current date based on the current millisecond.


String toDate = "07/1/2012";

DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT);
Calendar currentDateCal = Calendar.getInstance();

// Zero out the hour, minute, second, and millisecond.
currentDateCal.set(Calendar.HOUR_OF_DAY, 0);
currentDateCal.set(Calendar.MINUTE, 0);
currentDateCal.set(Calendar.SECOND, 0);
currentDateCal.set(Calendar.MILLISECOND, 0);

Date currentDate = currentDateCal.getTime();

Date toDt;

try
{
     toDt = df.parse(toDate);
}
catch (ParseException e)
{
     toDt = null;
     System.out.println(e.getMessage());
}

if (currentDate.equals(toDt))
{
     System.out.println(currentDate);  // Displays the current date.

     //Rest of the stuff.
}

String toDate = "07/12/2012";
try
{
     if (new SimpleDateFormat("MM/dd/yyyy").parse(toDate).getTime() / (1000 * 60 * 60 * 24) >= System.currentTimeMillis() / (1000 * 60 * 60 * 24)) 
     {
         System.out.println("True");
     }
     else
     {
         System.out.println("Untrue");
     }
}
catch(ParseException ex)
{
     Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}

String toDateAsString = "07/12/2012";
Date toDate=null;

try
{
    toDate = new SimpleDateFormat("MM/dd/yyyy").parse(toDateAsString);
}
catch (ParseException ex)
{
    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}

long toDateAsTimestamp = toDate.getTime();
long currentTimestamp = System.currentTimeMillis();
long getRidOfTime = 1000 * 60 * 60 * 24;
long toDateAsTimestampWithoutTime = toDateAsTimestamp / getRidOfTime;
long currentTimestampWithoutTime = currentTimestamp / getRidOfTime;

if (toDateAsTimestampWithoutTime >= currentTimestampWithoutTime)
{
    System.out.println("True");
}
else
{
    System.out.println("False");
}

The JodaTime's variant:

String toDateAsString = "07/01/2012";
DateTime toDate = DateTimeFormat.forPattern("MM/d/yyyy").parseDateTime(toDateAsString);
DateTime now = new DateTime();

if (!toDate.toLocalDate().isBefore(now.toLocalDate()))
{
    System.out.println("True");
} 
else
{
    System.out.println("False");
}


回答3:

why don't you compare the time in milliseconds?

Date d;
Calendar c;
System.out.println(d.getTime() == c.getTimeInMillis());


回答4:

Since, you tagged this Question with DateTime, i assume you use Joda already

...
//Initialize Calendar and Date Object

DateTime d1 = new DateTime(c.getTime());
DateTime d2 = new DateTime(d.getTime());

// Convert d1 and d2 to LocalDate say ld1 and ld2 since, Java Date defaults to GMT

ld1.compareTo(ld2); 

?



回答5:

I had to do this today and the answers in this post helped my solve my problem. I know all my timezones are the same like the OPs. And I don't have the liberty to use Joda time in my legacy code so for the benefit of others who have the same conditions, here is how I did it with vanilla Java.

Methodology:

  • java.sql.Time has a getTime() due to inheritance from java.util.Date. Using this method, one can create a java.util.Date object that represents just the time portion since Java epoch.
  • For comparison, one must convert the desired java.util.Calendar object to produce a java.util.Date object that represents another time since Java epoch.
  • Since the date parts are now equivalent, any comparison between the 2 objects would only compare the time parts producing the desired result.

Without further adieu, here is the code:

import java.sql.Time;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

public class Test {

    /**
     * Method to convert a calendar object to java's epoch date
     * keeping only the time information
     */
    public static Date toEpochDate(Calendar calendar) {
        return new Date(Time.valueOf(new SimpleDateFormat("HH:mm:ss").format(calendar.getTime())).getTime());
    }

    public static void main(String[] args) {

        // create any calendar object
        Calendar someTime = Calendar.getInstance();
        someTime.set(Calendar.HOUR_OF_DAY, 17);
        someTime.set(Calendar.MINUTE, 0);
        someTime.set(Calendar.SECOND, 0);

        // convert it to java epoch date
        Date someDate = toEpochDate(someTime);

        // create a date object from java.sql.Time
        Date fromSqlTime = new Date(Time.valueOf("17:00:00").getTime());

        // now do the comparison
        System.out.println("Some Date: " + someDate.toString());
        System.out.println("Sql Time: " + fromSqlTime.toString());
        System.out.println("Are they equal? " + someDate.equals(fromSqlTime));
    }
}

The above produces the following output:

Some Date: Thu Jan 01 17:00:00 EST 1970
Sql Time: Thu Jan 01 17:00:00 EST 1970
Are they equal? true

Using the above methodology, and by changing .equals() to .before() or .after(), various time comparison convenience methods can be created.