I have this code below:
Date now = CalendarUtils.getCalendar(getDefaultTimeZone())
.getTime();
The CalendarUtils class has the below methods
public static Calendar getCalendar(final TimeZone tz) {
return getCalendar(CalendarUtils.getDate(), tz);
}
public static Calendar getCalendar(final Date time, final TimeZone tz) {
final GregorianCalendar calendar = new GregorianCalendar();
calendar.setTimeZone(tz);
calendar.setTime(time);
return calendar;
}
public static Date getDate() {
return CalendarUtils.getDate(System.currentTimeMillis());
}
Where the getDefaultTimeZone() returns a timezone object in a specific timezone. Let's say Europe/Madrid.
However my application is running on a server in Rome.
The problem is that the code above is used to get the local time of Madrid. So at 12:30 am in Rome on Aug. 8th it is still 11:30 pm Aug. 7th in Madrid.
When I use
Date startOfDay = DateUtils.truncate(now, Calendar.DATE);
I would expect Aug. 7th 00:00:00 instead I get Aug 8th 00:00:00
I have read how Date returns the Millis from the Epoch but I would expect that it would return the millis from the Epoch of the date I ask from the Calendar.
When I use the query below at 12:30 am Aug 8th Rome time utilizing the two dates (now and startOfDay) I get results for the 8th of Aug instead the 7th (which is the local time in Madrid).
public BigInteger getSumForDates(Date fromDate, Date toDate) {
Session session = sessionFactory.openSession();
BigInteger sum;
try{
sum = (BigInteger)session
.createSQLQuery(
"SELECT SUM(column) FROM table
WHERE (column2 at time zone vas_tz()) >=:fromDate
AND (column2 at time zone vas_tz()) < :toDate")
.setTimestamp("fromDate", fromDate)
.setTimestamp("toDate", toDate).uniqueResult();
}catch (final HibernateException e){
LOGGER.error(e.getMessage());
throw new ProjectRuntimeException();
}finally{
session.close();
}
EDIT
The DateUtils is the one from package org.apache.commons.lang.time;
public static Date truncate(Date date, int field) {
if (date == null) {
throw new IllegalArgumentException("The date must not be null");
}
Calendar gval = Calendar.getInstance();
gval.setTime(date);
modify(gval, field, MODIFY_TRUNCATE);
return gval.getTime();
}
When I say to return the millis for the date I have asked the Calendar for, I meant that if the calendar has supplied Aug 7th 11:30 pm (since I provided a timezone) then I would expect the millis from the Epoch until Aug 7th 11:30 adjusted for that timezone. Is this an incorrect expectation?
I have read how Date returns the Millis from the Epoch but I would expect that it would return the millis from the Epoch of the date I ask from the Calendar.
Then your expectation is incorrect - or you're not expressing your expectation clearly. There's only one Unix epoch: it's midnight UTC. A Date has no concept of a time zone - it's just the number of milliseconds since the Unix epoch.
It's not clear what your DateUtils class is, but anything which claims to truncate a Date to a day without specifying a time zone is somewhat dubious.
I would strongly advise you to use Joda Time or the Java 8 java.time classes - they're much simpler to work with than java.util.*. If you must use java.util.Date and java.util.Calendar, you'll need to work out which time zone you're interested, and specify that appropriately - using Calendar, not Date - when performing operations such as "truncate to day".
Related
I'm retrieving a timestamp object from a database using ResultSet.getTimestamp(), but I'd like an easy way to get the date in the format of MM/DD/YYYY and the time in a format of HH:MM xx. I was tinkering around, it it looks as though I can do such by making use of the Date and/or DateTime objects within Java. Is that the best way to go, or do I even need to convert the timestamp to accomplish this? Any recommendations would be helpful.
....
while(resultSet.next()) {
Timestamp dtStart = resultSet.getTimestamp("dtStart");
Timestamp dtEnd = resultSet.getTimestamp("dtEnd");
// I would like to then have the date and time
// converted into the formats mentioned...
....
}
....
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateTest {
public static void main(String[] args) {
Timestamp timestamp = new Timestamp(System.currentTimeMillis());
Date date = new Date(timestamp.getTime());
// S is the millisecond
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("MM/dd/yyyy' 'HH:mm:ss:S");
System.out.println(simpleDateFormat.format(timestamp));
System.out.println(simpleDateFormat.format(date));
}
}
java.sql.Timestamp is a subclass of java.util.Date. So, just upcast it.
Date dtStart = resultSet.getTimestamp("dtStart");
Date dtEnd = resultSet.getTimestamp("dtEnd");
Using SimpleDateFormat and creating Joda DateTime should be straightforward from this point on.
java.time
Modern answer: use java.time, the modern Java date and time API, for your date and time work. Back in 2011 it was right to use the Timestamp class, but since JDBC 4.2 it is no longer advised.
For your work we need a time zone and a couple of formatters. We may as well declare them static:
static ZoneId zone = ZoneId.of("America/Marigot");
static DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("MM/dd/uuuu");
static DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm xx");
Now the code could be for example:
while(resultSet.next()) {
ZonedDateTime dtStart = resultSet.getObject("dtStart", OffsetDateTime.class)
.atZoneSameInstant(zone);
// I would like to then have the date and time
// converted into the formats mentioned...
String dateFormatted = dtStart.format(dateFormatter);
String timeFormatted = dtStart.format(timeFormatter);
System.out.format("Date: %s; time: %s%n", dateFormatted, timeFormatted);
}
Example output (using the time your question was asked):
Date: 09/20/2011; time: 18:13 -0400
In your database timestamp with time zone is recommended for timestamps. If this is what you’ve got, retrieve an OffsetDateTime as I am doing in the code. I am also converting the retrieved value to the user’s time zone before formatting date and time separately. As time zone I supplied America/Marigot as an example, please supply your own. You may also leave out the time zone conversion if you don’t want any, of course.
If the datatype in SQL is a mere timestamp without time zone, retrieve a LocalDateTime instead. For example:
ZonedDateTime dtStart = resultSet.getObject("dtStart", LocalDateTime.class)
.atZone(zone);
No matter the details I trust you to do similarly for dtEnd.
I wasn’t sure what you meant by the xx in HH:MM xx. I just left it in the format pattern string, which yields the UTC offset in hours and minutes without colon.
Link: Oracle tutorial: Date Time explaining how to use java.time.
You can also get DateTime object from timestamp, including your current daylight saving time:
public DateTime getDateTimeFromTimestamp(Long value) {
TimeZone timeZone = TimeZone.getDefault();
long offset = timeZone.getOffset(value);
if (offset < 0) {
value -= offset;
} else {
value += offset;
}
return new DateTime(value);
}
LocalDateTime dtStart = rs.getTimestamp("dtStart").toLocalDateTime();
Converts this Timestamp object to a code LocalDateTime.
The conversion creates a code LocalDateTime that represents the
same year, month, day of month, hours, minutes, seconds and nanos
date-time value as this code Timestamp in the local time zone.
since 1.8
(Sorry for my english...)
To represent a gregorian calendar date before 15 Oct 1582 (starting date for Gregorian Calendar) it is possible to use a proleptic GregorianCalendar. Such a Calendar allows to represent dates prior to 15 Oct 1582 using the gregorian calendar system, also if it didn't exist at that time.
Two possible methods to create a new proleptic GregorianCalendar are the following (I report this for test purposes, but it is not essential):
GregorianCalendar proleptic = null;
proleptic = new GregorianCalendar();
proleptic.clear();
proleptic.setGregorianChange(new Date(Long.MIN_VALUE));
proleptic.set(Calendar.DAY_OF_MONTH, 8);
proleptic.set(Calendar.MONTH, Calendar.OCTOBER);
proleptic.set(Calendar.YEAR, 1582);
System.out.println("proleptic_calendar_8Oct1582 [DAY_OF_MONTH ["+proleptic.get(Calendar.DAY_OF_MONTH)+"], MONTH ["+proleptic.get(Calendar.MONTH)+"], YEAR ["+proleptic.get(Calendar.YEAR)+"], in millis ["+proleptic.getTimeInMillis()+"]");
GregorianCalendar prolepticFromXML = null;
String newDate = "1582-10-08";
DatatypeFactory datatypeFactory = null;
try {
datatypeFactory = DatatypeFactory.newInstance();
prolepticFromXML = datatypeFactory.newXMLGregorianCalendar(newDate).toGregorianCalendar();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("prolepticFromXML_8Oct1582 [DAY_OF_MONTH ["+prolepticFromXML.get(Calendar.DAY_OF_MONTH)+"], MONTH ["+prolepticFromXML.get(Calendar.MONTH)+"], YEAR ["+prolepticFromXML.get(Calendar.YEAR)+"], in millis ["+prolepticFromXML.getTimeInMillis()+"]");
System.out.println("millis matches: ["+(proleptic.getTimeInMillis() == prolepticFromXML.getTimeInMillis())+"]
output:
proleptic_calendar_8Oct1582 [DAY_OF_MONTH [8], MONTH [9], YEAR [1582], in millis [-12219901200000]
prolepticFromXML_8Oct1582 [DAY_OF_MONTH [8], MONTH [9], YEAR [1582], in millis [-12219901200000]
millis matches: [true]
Now we imagine to receive a string from an input source (a web form, a soap request, etc) and to build with it a proleptic GregorianCalendar, we can call it myCalendarField, .
Then, I'd like to write this date on a mysql database, in a column of type DATE.
I use Hibernate as persistence framework and imagine the myCalendarField is a field mapped into an Entity class
#Temporal(TemporalType.DATE)
#Column(name = "a_test_date_field")
public Calendar getMyCalendarField() {
return this.myCalendarField;
}
following the code starting by org.hibernate.type.CalendarDateType, that manages the mapping between java Calendar and sql DATE, I found that it calls the method
public void setDate(int parameterIndex, java.sql.Date x, Calendar cal)
in com.mysql.jdbc.PreparedStatement, available in the mysql connector,
passing a
new java.sql.Date( myCalendarField.getTime().getTime() );
as x
Now, the setDate method uses a SimpleDateFormat in order to convert the passed Date in string, prior to convert this string on byte[] and following the work-flow.
To format the date the connector does something like this:
SimpleDateFormat ddf = new SimpleDateFormat("''yyyy-MM-dd''", Locale.US);
ddf.setTimeZone(cal.getTimeZone());
String timeString = ddf.format(x);
at this point the format method of java.text.SimpleDateFormat does something like this
Calendar calendar = null;
calendar = Calendar.getInstance(TimeZone.getDefault(), Locale.US);
calendar.setTime(x);
and uses the new instantiated calendar to get all date and time informations to build the output formatted string.
What happens is then that the new created Calendar is not proleptic anymore, than the dates prior to 15 Oct 1582 are converted to julian dates.
As a consequence of this, we obtain on DB a date different from the one received in input.
So, if a java web application receives for example 8 oct 1582, treats it as a proleptic Gregorian Calendar and wants to save it on a DATE field on a mysql DB, the date persisted becomes 28 Sep 1582.
I found no way, at the moment, to persist the original input date without modifications.
Are my conclusions correct? Do you know any way to persist on a mySql DB a date prior then 15 Oct 1582 as proleptic GregorianCalendar, using Java + Hibernate + my sql connector?
EDIT
In 2018 the jdbc connector bug, opened following this post, has been fixed.
I m facing a problem:I want to get current time of GMT TimeZone in long.
I m using the following code as given below:
TimeZone timeZoneGmt = TimeZone.getTimeZone("GMT");
long gmtCurrentTime = getCurrentTimeInSpecificTimeZone(timeZoneGmt);
public static long getCurrentTimeInSpecificTimeZone(TimeZone timeZone) {
Calendar cal = Calendar.getInstance();
cal.setTimeZone(timeZone);
long finalValue = 0;
SimpleDateFormat sdf = new SimpleDateFormat(
"MMM dd yyyy hh:mm:ss:SSSaaa");
sdf.setTimeZone(timeZone);
Date finalDate = null;
String date = sdf.format(cal.getTime());
try {
finalDate = sdf.parse(date);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finalValue = finalDate.getTime();
return finalValue;
}
As given in, above method
while formatting
String date = sdf.format(cal.getTime());
I m getting correct current time in GMT but as i do parsing by following code:
finalDate=sdf.parse(date);
Date got changed from current GMT time to 15:35:16 IST 2013 that is current time of my system.
I tried with Calendar as well in another way:
TimeZone timeZoneGmt=TimeZone.get("GMT");
Calendar calGmt = Calendar.getInstance();
calGmt.setTimeZone(timeZoneGmt);
long finalGmtValue = 0;
finalGmtValue = calGmt.getTimeInMillis();
System.out.println("Date......" + calGmt.getTime());
but still getting date as current time of my System Thu Jan 23 15:58:16 IST 2014 Not getting GMT current time.
You've misunderstood how Date works. A Date doesn't have a time zone - if you use Date.toString() you'll always see the default time zone. The long value in a Date is purely the number of milliseconds since the Unix epoch: it doesn't have any concept of time zone or calendar system.
If you want to represent a date and time in a particular time zone and calendar, use Calendar instead - but for getting "the current date and time as a long" you can just use System.currentTimeMillis(), which again does not have anything to do with the system time zone.
Additionally, even if you did want to do manipulation like this, you shouldn't be using string conversions. You're not conceptually performing any string conversions, so why introduce them?
If your aim is to display (as a string) the current date and time in a particular time zone, you should just use something like:
Date date = new Date(); // This will use the current time
SimpleDateFormat format = new SimpleDateFormat(...); // Pattern and locale
format.setTimeZone(zone); // The zone you want to display in
String formattedText = format.format(date);
When working with date and time APIs - particularly bad ones like the Java Calendar/Date API - it's very important that you understand exactly what each value in your system represents.
I have written two functions - today() and todayUTC() - as:
public static Date today() {
Calendar cal = Calendar.getInstance();
return cal.getTime();
}
public static Date todayUTC() {
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
return cal.getTime();
}
But when I print the results of these functions using:
public void todayTest() {
Date date1 = OOTBFunctions.today();
System.out.println("today: "+date1);
Date dateUTC1 = OOTBFunctions.todayUTC();
System.out.println("todayUTC: "+dateUTC1);
}
I saw that both statements print the same value i.e.
today: Thu Aug 30 14:48:56 PDT 2012
todayUTC: Thu Aug 30 14:48:56 PDT 2012
Can anybody suggest what am I missing in UTC function that I am getting local timezone date.
Java uses the default Locale while printing and that is why you see that behavior. Use code like below to format and print it in the locale/format you want. Remember
When you create a Date object, it is always in UTC.
Display the date in the Locale of the user.
Store the date in UTC.
Code
final SimpleDateFormat sdf = new SimpleDateFormat("the format you want");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
final String utcTime = sdf.format(new Date());
You doesn't need both today() and todayUTC() methods. keep and like below
public static Date nowInUTC()
{
return new Date();
}
You doesn't need to test anything.
Both of your methods will return the same value - a Date object doesn't have any notion of a time zone (unlike a Calendar). A Date just represents an instant in time, stored internally as the number of milliseconds since midnight January 1st 1970, UTC. Effectively, you've got two methods which are equivalent to:
return new Date(System.currentTimeMillis());
Date.toString() always uses the system default time zone.
If you want to maintain a date/time with a time zone, consider just using Calendar. If you want to format a particular instant in time in a time zone, just use SimpleDateFormat having set the time zone.
Ideally, change to use Joda Time instead of Date or Calendar though - it's a much cleaner API.
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);
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:
Create a Calendar from your date
Copy timezone from the calendar you already use
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:
SQL Server TZ
JVM's default TZ
Calendar's TZ
All three must be the same so that any comparison would make any sense.
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");
}
why don't you compare the time in milliseconds?
Date d;
Calendar c;
System.out.println(d.getTime() == c.getTimeInMillis());
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);
?
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.