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 getDate(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.
Related
I want my String "10:10" to be converted into time in a format of hh:mm instead of MM/dd/yyyy hh:mm:ss aa
Date date;
SimpleDateFormat sdf;
sdf = new SimpleDateFormat("hh:mm");
try
{
date = sdf.parse(a.getString("time").toString());
Log.d(TAG, "onCreate: "+date);
Log.d(TAG, "onCreate: "+a.getString("time"));
}
catch (ParseException e) {
e.printStackTrace();
}
But i am getting this in my logcat
D/MTAG: onCreate: Thu Jan 01 10:00:00 GMT+05:00 1970
D/MTAG: onCreate: 10:00
String timeString = "10:10";
LocalTime time = LocalTime.parse(timeString);
System.out.println(time);
This prints
10:10
I am cheating a bit, though. The way I read your question, you asked for a date-time object with the format HH:mm in it. Neither a LocalTime object (used in the above snippet) nor a Date (used in your code) can have a format in it. What you get when you concatenate the Date to a string or print the LocalTime is the result of the object’s toString method, and you cannot change this method (only in subclasses, and you don’t want that). In other words, when you want a specific format, you need to have that format in a string outside the date-time object.
The lucky part is that LocalTime.toString() produces the format you want (as long as the seconds and fraction of second are zero; otherwise they would be in the string too).
Will that work on your Android device? It will. LocalTime is a class of JSR-310 also known as java.time, the modern Java date and time API introduced nearly 4 years ago, early in 2014. JSR-310 has been backported to Java 6 and 7 in ThreeTen Backport, which in turn has been adapted to Android in ThreeTenABP. So get ThreeTenABP, add it to your project and start enjoying how much nicer it is to work with than the outdated date and time classes.
PS There’s a bug in your format pattern string in the question: Lowercase hh is for hour within AM or PM from 1 through 12, which works nicely when the hours are 10, but not always. I am convinced that you want uppercase HH for hour of day in the interval 0 through 23. When I run your code with a string of 12:12, I get Thu Jan 01 00:12:00 CET 1970. The hours are 0, not 12.
Links
Oracle tutorial: Date Time, explaining how to use java.time.
ThreeTen Backport project
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
Java Specification Request (JSR) 310, where the modern date and time API was first described.
Date and time formats are specified by date and time pattern strings.
Within date and time pattern strings, unquoted letters from 'A' to 'Z'
and from 'a' to 'z' are interpreted as pattern letters representing
the components of a date or time string. Text can be quoted using
single quotes (') to avoid interpretation. "''" represents a single
quote. All other characters are not interpreted; they're simply copied
into the output string during formatting or matched against the input
string during parsing.
Read Document
Try this:
DateFormat aFormatter = new SimpleDateFormat("HH:mm");
Date dt = aFormatter.parse("10:10");
Calendar aCalander = Calendar.getInstance();
aCalander.setTime(dt);
int hour = aCalander.get(Calendar.HOUR);
int minute = aCalander.get(Calendar.MINUTE);
When a Date is created, it will be in the format of "Thu Jan 01 10:00:00 GMT+05:00 1970" as you mention in your output. So if you want to display and play around with the format of the date you should use the format method in SimpleDateFormat. I hope the below code help you understand better.
//formatting date in Java using SimpleDateFormat
String date_s = "10:10";
SimpleDateFormat dt = new SimpleDateFormat("hh:mm");
Date date = dt.parse(date_s);
System.out.println(date);
System.out.println(dt.format(date));
I'm using java.util.Date. The expression:
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2016-10-16 00:00:00").toString()
is returning "Sun Oct 16 01:00:00 BRST 2016" (a wrong date) for this particular date, but a correct response on most other dates.
I also tried a format string taken from Oracle docs: "yyyy-MM-dd'T'HH:mm:ss.SSSZ" and a specific date: "2016-10-16T00:00:00.000-0300" and got the same "error" (I suppose), one hour ahead:
Sun Oct 16 01:00:00 BRST 2016
That usually happens due to Daylight Saving Time (DST) (also known as "summer time"). Based on the date/time, and on the output you've got (Sun Oct 16 01:00:00 BRST 2016), I suppose it's Brazil's DST (BRST is the abbreviation for Brazilian's summer time).
SimpleDateFormat uses the JVM's default timezone (if you don't specify one), so probably your default zone is America/Sao_Paulo or Brazil/East (you can check that by calling TimeZone.getDefault().getID()).
In America/Sao_Paulo timezone, DST started at October 16th 2016: at midnight, clocks shifted 1 hour forward from midnight to 1 AM (and the offset changed from -03:00 to -02:00). So all local times between 00:00 and 00:59 didn't exist in this timezone (you can also think that clocks changed from 23:59:59.999999999 directly to 01:00).
That's why this specific date in midnight (which didn't exist in this timezone) is automatically shifted to the next valid moment (1 AM). But if I set a specific timezone in the formatter, this won't happen:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// set formatter to use UTC (instead of JVM default timezone)
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
// parse it as midnight (no shift to 01:00)
Date date = sdf.parse("2016-10-16 00:00:00");
In this case, I'm using UTC, which has no DST effects. But remind that the date created above will be equivalent to midnight in UTC (which is the same instant as October 15th 2016 at 9 PM in Brazil (the day before) - maybe it's not what you want).
Be aware of that before changing the timezone: if you want a specific instant (a precise point in time), changing the timezone will affect the final result. If you just want to consider the date/time values and don't care about in what timezone it is (treating the value as it's a "local date/time"), just set the formatter to use UTC, to avoid DST effects (an ugly workaround, IMO, but just because the java.util.Date API doesn't have specific types for local date/times).
But anyway, this is not an error. It's the expected behaviour (DST and timezones have lots of strange and non-intuitive behaviours, but that's the way it is).
Java new Date/Time API
The old classes (Date, Calendar and SimpleDateFormat) have lots of problems and design issues, and they're being replaced by the new APIs.
If you're using Java 8, consider using the new java.time API. It's easier, less bugged and less error-prone than the old APIs.
If you're using Java 6 or 7, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, you'll also need the ThreeTenABP (more on how to use it here).
The code below works for both.
The only difference is the package names (in Java 8 is java.time and in ThreeTen Backport (or Android's ThreeTenABP) is org.threeten.bp), but the classes and methods names are the same.
This new API has lots of new types that best suit different use-cases. In your case, if you want just the date and time fields and don't care about timezones, you can use a LocalDateTime. To parse it, just use a DateTimeFormatter:
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime dt = LocalDateTime.parse("2016-10-16 00:00:00", fmt);
System.out.println(dt); // 2016-10-16T00:00
This will ignore DST effects, because a LocalDateTime has no timezone information.
But if you want to consider the timezone, you can convert this to a ZonedDateTime, using a ZoneId to get the timezone:
// convert to a timezone
ZonedDateTime z = dt.atZone(ZoneId.of("America/Sao_Paulo"));
System.out.println(z); // 2016-10-16T01:00-02:00[America/Sao_Paulo]
In this case, note that the time was adjusted to 1 AM, because I converted to America/Sao_Paulo timezone, so the DST effects were considered, as already explained above.
With this new API we can look closer at what's happening in this specific timezone, for this particular date/time. First I'll create a ZonedDateTime that corresponds to October 15th 2016, at 23:59:59 in America/Sao_Paulo timezone, and then I'll add 1 second to it:
// October 15th 2016, at 23:59:59 in Sao Paulo timezone
ZonedDateTime z = ZonedDateTime.of(2016, 10, 15, 23, 59, 59, 0, ZoneId.of("America/Sao_Paulo"));
System.out.println(z); // 2016-10-15T23:59:59-03:00[America/Sao_Paulo]
System.out.println(z.plusSeconds(1)); // 2016-10-16T01:00-02:00[America/Sao_Paulo]
Note that the original date is in offset -03:00 (3 hours behind UTC, which is the standard offset for America/Sao_Paulo timezone). One second later, it should be midnight, but due to DST change, the clock shifts directly to 1 AM, and the offset changes to -02:00.
Even if I try to directly create October 16th 2016 at midnight in this timezone, the value will be corrected, because this local time doesn't exist in this timezone, due to DST shift:
// Try to create October 16th 2016, at midnight in Sao Paulo timezone
ZonedDateTime z = ZonedDateTime.of(2016, 10, 16, 0, 0, 0, 0, ZoneId.of("America/Sao_Paulo"));
System.out.println(z); // 2016-10-16T01:00-02:00[America/Sao_Paulo]
So, it's not an error. October 16th 2016 at midnight in America/Sao_Paulo timezone doesn't exist due to a DST change, and the API's automatically corrects this to the next valid moment (which is, in this case, 1 AM).
The API uses IANA timezones names (always in the format Region/City, like America/Sao_Paulo or Europe/Berlin).
Avoid using the 3-letter abbreviations (like CST or PST) because they are ambiguous and not standard.
You can get a list of available timezones (and choose the one that fits best your system) by calling ZoneId.getAvailableZoneIds().
You can also use the system's default timezone with ZoneId.systemDefault(), but this can be changed without notice, even at runtime, so it's better to explicity use a specific one.
Your problem is probably the timezone, so you could use:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
Here is the original answer.
I read many posts at SO and tested most of them. None of them is working for me. Here is my code:
DateTimeZone fromTimeZone = DateTimeZone.forID("America/New_York");
DateTimeZone toTimeZone = DateTimeZone.forID("US/Central");
Date now = new Date();
DateTime dateTime = new DateTime(now, fromTimeZone);
DateTime newDateTime = dateTime.withZone(toTimeZone);
System.out.println(dateTime.toDate() + "--" + newDateTime.toDate());
Here is what I got in print:
Tue Aug 22 13:08:13 EDT 2017--Tue Aug 22 13:08:13 EDT 2017
I am hoping to display "Tue Aug 22 12:08:13 CDT 2017" for the second time zone.
A java.util.Date doesn't have timezone information. Joda's DateTime has, but it's wrapped into a Chronology to translate this instant to "human readable" date/time fields.
But in the end, both objects just represent points (instants) in the time-line.
Just check the values of dateTime.getMillis(), newDateTime.getMillis(), dateTime.toDate().getTime() and newDateTime.toDate().getTime(). They will all be exactly the same, and this value represents the number of milliseconds since epoch (1970-01-01T00:00Z).
The timezone passed to the DateTime object just affects the output of toString() (when this milliseconds value is "translated" to a local date and time), but it doesn't change the milliseconds value itself. So if you do:
DateTime dateTime = new DateTime(now, fromTimeZone);
System.out.println(dateTime);
It will print the date and time that's equivalent to the milliseconds value, but converted to the fromTimeZone (America/New_York):
2017-08-22T13:33:08.345-04:00
The withZone method just sets to a different timezone, but keeps the same milliseconds value:
DateTime newDateTime = dateTime.withZone(toTimeZone);
System.out.println(newDateTime);
The code above keeps the instant (the milliseconds value), but prints the equivalent date and time in the toTimeZone (US/Central):
2017-08-22T12:33:08.345-05:00
The .toDate() method returns a java.util.Date, which just contains the same milliseconds value, and no timezone information. Then, System.out.println implicity calls Date::toString() method, and this converts the milliseconds value to the JVM's default timezone. In this case both will be:
Tue Aug 22 13:33:08 EDT 2017
Because both dates represent the same instant (the same number of milliseconds since epoch).
If you want to get a String that contains the date in a specific format, you can use a org.joda.time.format.DateTimeFormatter:
DateTimeFormatter fmt = DateTimeFormat.forPattern("EEE MMM dd HH:mm:ss z yyyy").withLocale(Locale.ENGLISH);
System.out.println(fmt.print(new DateTime(DateTimeZone.forID("US/Central"))));
There's no need to convert dates objects, because actually no conversion is really happening: all methods above don't change the milliseconds value.
Also note that I used a java.util.Locale to make sure the month and day of week are in English. If you don't specify a locale, the JVM default will be used, and it's not guaranteed to always be English (and it can also be changed, even at runtime, so it's better to always specify it).
Then I get the current date and set the timezone to be used when printing it. Note that you can get a DateTime directly, there's no need to create a java.util.Date.
The output will be:
Tue Aug 22 12:33:08 CDT 2017
To get exactly the same output you want (with both dates), you can do:
DateTimeFormatter fmt = DateTimeFormat.forPattern("EEE MMM dd HH:mm:ss z yyyy").withLocale(Locale.ENGLISH);
DateTime nowNy = new DateTime(DateTimeZone.forID("America/New_York"));
DateTime nowCentral = nowNy.withZone(DateTimeZone.forID("US/Central"));
System.out.println(fmt.print(nowNy) + "--" + fmt.print(nowCentral));
The output will be:
Tue Aug 22 13:33:08 EDT 2017--Tue Aug 22 12:33:08 CDT 2017
Java new Date/Time API
Joda-Time is in maintainance mode and being replaced by the new APIs, so I don't recommend start a new project with it. Even in joda's website it says: "Note that Joda-Time is considered to be a largely “finished” project. No major enhancements are planned. If using Java SE 8, please migrate to java.time (JSR-310)." (if you don't want to or can't migrate from Joda to another API, you can desconsider this section).
If you're using Java 8, consider using the new java.time API. It's easier, less bugged and less error-prone than the old APIs.
If you're using Java <= 7, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, there's the ThreeTenABP (more on how to use it here).
The code below works for both.
The only difference is the package names (in Java 8 is java.time and in ThreeTen Backport (or Android's ThreeTenABP) is org.threeten.bp), but the classes and methods names are the same.
The relevant classes are DateTimeFormatter (to format the date to a String in a specific format), ZonedDateTime (which represents a date and time in a specific timezone) and a ZoneId (which represents a timezone):
// formatter - use English locale for month and day of week
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss z yyyy", Locale.ENGLISH);
// current date/time in New York timezone
ZonedDateTime nowNy = ZonedDateTime.now(ZoneId.of("America/New_York"));
// convert to another timezone (US/Central)
ZonedDateTime nowCentral = nowNy.withZoneSameInstant(ZoneId.of("US/Central"));
// format dates
System.out.println(fmt.format(nowNy) + "--" + fmt.format(nowCentral));
The output is the same as above.
I need today's date - and zero anything else (" 05/06/08 00:00:00 ")
I've tried
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR, 0);
Date date1 = calendar.getTime();
System.out.println(date1);
Run: (This is seriously messed up)
If the hour on the computer is < 12:00 at noon : Sun Mar 08 00:44:39 IST 2009
If the hour on the computer is > 12:00 at noon : Sun Mar 08 12:46:53 IST 2009
So I gave this up.
All the Date's setters are deprecated (except the epoch time) - so I don't want to use them either
The only thing I could think of is
Calendar calendar = Calendar.getInstance();
SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
String sDate = dateFormat.format(calendar.getTime());
Date today = dateFormat.parse(sDate);
But this is such a lame code I can't bring myself to write it.
Any other option?
Thanks!
I use this:
public static Date startOfDay(Date date) {
Calendar dCal = Calendar.getInstance();
dCal.setTime(date);
dCal.set(Calendar.HOUR_OF_DAY, 0);
dCal.set(Calendar.MINUTE, 0);
dCal.set(Calendar.SECOND, 0);
dCal.set(Calendar.MILLISECOND, 0);
return dCal.getTime();
}
My standard advice for Java date/time questions: don't use java.util.{Calendar,Date}. Use Joda Time. That way you can represent a date as a date (with no associated time zone), instead of a date/time. Or you could use a DateMidnight if that's what you want to represent. (Be careful of combinations of time zone and date where there is no midnight though...)
What do you need to use the Date with? If you can get away with changing to use Joda throughout, that's great. Otherwise, you can use Joda to do what you want and then convert to milliseconds (and then to java.util.Date) when you really need to.
(Michael's solution when using Date/Calendar is fine if you really want to stick within a broken API... but I can't overstate how much better Joda is...)
You should use HOUR_OF_DAY instead of HOUR and combine it with MINUTE and SECOND also.
import java.util.Calendar;
import static java.util.Calendar.HOUR_OF_DAY;
import static java.util.Calendar.MINUTE;
import static java.util.Calendar.SECOND;
import static java.util.Calendar.MILLISECOND;
public class Today {
public static void main( String [] args ) {
Calendar cal = Calendar.getInstance();
cal.set( HOUR_OF_DAY, 0 );
cal.set( MINUTE, 0 );
cal.set( SECOND, 0 );
cal.set( MILLISECOND, 0 );
System.out.println( cal.getTime() );
}
}
The results you are getting are due to HOUR is used to AM/PM while HOUR_OF_DAY is 24 hrs.
HOUR_OF_DAY:
Field number for get and set indicating the hour of the day. HOUR_OF_DAY is used for the 24-hour clock. E.g., at 10:04:15.250 PM the HOUR_OF_DAY is 22.
HOUR:
Field number for get and set indicating the hour of the morning or afternoon. HOUR is used for the 12-hour clock (0 - 11). Noon and midnight are represented by 0, not by 12. E.g., at 10:04:15.250 PM the HOUR is 10.
The time component is not just hours (and Calendar.HOUR is, as you have noticed, AM/PM).
You need to set all of the time fields to 0: HOUR_OF_DAY, MINUTE, SECOND, MILLISECOND.
See Apache's commons-lang DateUtils.truncate()
java.time
The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.
Also, quoted below is a notice from the home page of Joda-Time:
Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.
Solution using java.time, the modern Date-Time API:
The modern Date-Time API has many types which truly represent a date or time or date-time in a specific timezone. You can choose from the following options as per your specific requirement:
If you are looking for a type that represents a date without a timezone, you can use LocalDate.now. The good news is that its variant, LocalDate#now(ZoneId) returns the current date from the system clock in the specified time-zone.
If you are looking for an object that represents a date without a timezone, and with time units set to zero, you can call LocalDate#atStartOfDay on the object obtained with Option#1.
If you are looking for an Instant representing the Date-Time object obtained with Option#2, you can attach this object with ZoneId.of("Etc/UTC") using LocalDateTime#atZone to obtain a ZonedDateTime and convert the same into an Instant using ZonedDateTime#toInstant.
Demo:
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class Main {
public static void main(String[] args) {
LocalDate todayInSystemTz = LocalDate.now();
System.out.println(todayInSystemTz);
LocalDate todayInIndia = LocalDate.now(ZoneId.of("Asia/Kolkata"));
System.out.println(todayInIndia);
LocalDateTime todayInSystemTzWithZeroTimeUnits = todayInSystemTz.atStartOfDay();
System.out.println(todayInSystemTzWithZeroTimeUnits);
ZonedDateTime todayInUtcWithZeroTimeUnits = todayInSystemTzWithZeroTimeUnits.atZone(ZoneId.of("Etc/UTC"));
System.out.println(todayInUtcWithZeroTimeUnits);
Instant instant = todayInUtcWithZeroTimeUnits.toInstant();
System.out.println(instant);
// Can I represent the obtained Instant in India?
System.out.println(instant.atZone(ZoneId.of("Asia/Kolkata")));
// Can I represent the obtained Instant in New York?
System.out.println(instant.atZone(ZoneId.of("America/New_York")));
}
}
Output:
2021-06-20
2021-06-20
2021-06-20T00:00
2021-06-20T00:00Z[Etc/UTC]
2021-06-20T00:00:00Z
2021-06-20T05:30+05:30[Asia/Kolkata]
2021-06-19T20:00-04:00[America/New_York]
ONLINE DEMO
The Z in the output is the timezone designator for zero-timezone offset. It stands for Zulu and specifies the Etc/UTC timezone (which has the timezone offset of +00:00 hours).
For any reason, if you need to convert this object of Instant to an object of java.util.Date**, you can do so as follows:
Date date = Date.from(instant);
Learn more about the modern Date-Time API from Trail: Date Time.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
**
A java.util.Date object simply represents the number of milliseconds since the standard base time known as "the epoch", namely January 1, 1970, 00:00:00 GMT (or UTC). Since it does not hold any timezone information, its toString function applies the JVM's timezone to return a String in the format, EEE MMM dd HH:mm:ss zzz yyyy, derived from this milliseconds value. To get the String representation of the java.util.Date object in a different format and timezone, you need to use SimpleDateFormat with the desired format and the applicable timezone e.g.
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("America/New_York"));
String strDateNewYork = sdf.format(date);
sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
String strDateUtc = sdf.format(date);
As mentioned above you should use
Calendar.HOUR_OF_DAY
As opposed to
Calendar.HOUR
Also you need to clear out the other fields (Calendar.MINUTE, Calendar.SECOND, and Calendar.MILLISECOND) by setting them to zero.
Sorry there's no easy way here. A pain, and that's why they're working on a new API for Java 7 I believe based on Joda Time.
...or you can do it the hacker way:
long MS_PER_DAY = 86400000L;
Date dateTime=new Date();
long offset = TimeZone.getDefault().getOffset(dateTime.getTime());
Date date= new Date(((dateTime.getTime()+offset)/MS_PER_DAY)*MS_PER_DAY-offset);
I know this is a very old question, no longer active, but it came to be on the top when I searched Google.
While all advise is very good, I can't believe no one simply answered:
Date date = new Date(System.currentTimeMillis());
System.out.println(date);
Which returns effectively, today's date.
Why the string manipulation?
Can you not just set the values you need on the Calendar object before converting to a Date using getTime()?
Another vote for JodaTime.
java.util.Date and Calendar are so bad they are broken. (And SimpleDateFormat is rubbish too!)
For what it's worth, Java 7 will include a new date time library based strongly around JodaTime.
I have a string from an email header, like Date: Mon, 27 Oct 2008 08:33:29 -0700. What I need is an instance of GregorianCalendar, that will represent the same moment. As easy as that -- how do I do it?
And for the fastest ones -- this is not going to work properly:
SimpleDateFormat format = ... // whatever you want
Date date = format.parse(myString)
GregorianCalendar calendar = new GregorianCalendar();
calendar.setTime(date)
because it will normalize the timezone to UTC (or your local machine time, depending on Java version). What I need is calendar.getTimeZone().getRawOffset() to return -7 * milisInAnHour.
I'd recommend looking into the Joda Time library, if that's an option. I'm normally against using a third-party library when the core platform provides similar functionality, but I made this an exception because the author of Joda Time is also behind JSR310, and Joda Time is basically going to be rolled into Java 7 eventually.
http://joda-time.sourceforge.net/
So anyway, if Joda Time is an option, something like this should work:
DateTimeFormatter formatter =
DateTimeFormat.forPattern("your pattern").withOffsetParsed();
DateTime dateTime = formatter.parseDateTime("your input");
GregorianCalendar cal = dateTime.toGregorianCalendar();
I hope this helps.
And for the fastest ones -- this is not going to work properly ...
because it will normalize the timezone to UTC (or your local machine time, depending on Java version). What I need is calendar.getTimeZone().getRawOffset() to return -7 * milisInAnHour.
Well technically this does work, because while it will return an object with TimeZone equal to the current system TimeZone, the time will be modified to account for the offset.
This code:
String dateString = "Mon, 27 Oct 2008 08:33:29 -0700";
DateFormat df = new SimpleDateFormat("E, dd MMM yyyy hh:mm:ss Z");
Date parsed = df.parse(dateString);
System.out.println("parsed date: " + parsed);
Calendar newCalendar = Calendar.getInstance();
newCalendar.setTime(parsed);
outputs:
parsed date: Mon Oct 27 11:33:29 EDT 2008
which technically is correct, since my system timezone is EDT / UTC minus four hours (which is three hours ahead of yours). If you express time as the number of milliseconds since January 1, 1970, 00:00:00 GMT (which is how the Date object stores it's date/time), then these date/times are equal, it's just the TimeZone that is different.
Your issue is really How do I convert a Date/Calendar into my timezone? For that, take a look at my response to the previous question How to handle calendar TimeZones using Java?
java.time
Solution using java.time, the modern date-time API:
The modern date-time API offers OffsetDateTime to represent a date-time object with a timezone offset. It can be converted to Instant which represents an instantaneous point on the timeline. An Instant is independent of any timezone i.e. it has a timezone offset of +00:00 hours, designated as Z in the ISO 8601 standards.
Instant#toEpochMilli converts this instant to the number of milliseconds from the epoch of 1970-01-01T00:00:00Z. This value can be set into an object of GregorianCalendar which will then represent the same moment.
Demo:
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String strDateTime = "Mon, 27 Oct 2008 08:33:29 -0700";
OffsetDateTime odt = OffsetDateTime.parse(strDateTime, DateTimeFormatter.RFC_1123_DATE_TIME);
System.out.println(odt);
// In case you want a time zone neutral object, convert to Instant
Instant instant = odt.toInstant();
System.out.println(instant);
// Edit: If the requirement is a GregorianCalendar having the offset from
// the string — typically for an old API not yet upgraded to java.time:
ZonedDateTime zdt = ZonedDateTime.parse(strDateTime, DateTimeFormatter.RFC_1123_DATE_TIME);
GregorianCalendar gc = GregorianCalendar.from(zdt);
System.out.println("As Date: " + gc.getTime());
System.out.println("Time zone ID: " + gc.getTimeZone().getID());
System.out.println("Hour of day: " + gc.get(Calendar.HOUR_OF_DAY));
// ...
}
}
Output:
2008-10-27T08:33:29-07:00
2008-10-27T15:33:29Z
As Date: Mon Oct 27 15:33:29 GMT 2008
Time zone ID: GMT-07:00
Hour of day: 8
Calling getTime() on the GregorianCalendar converts to a Date (another old and error-prone class) which doesn’t have a time zone, so the offset is lost. Printing the time zone ID and the hour of day demonstrates that both offset and time of day are preserved in the GregorianCalendar.
Learn more about the modern date-time API from Trail: Date Time.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.