I am saving date's in a file in the following format as a string.
Sat Jul 21 23:31:55 EDT 2012
How can I check if 24 hours have passed? I am a beginner so please explain it a little bit =)
I am not sure if I completely understood the question - do you have two dates for comparison or do you wish to keep checking periodically if 24 hours have elapsed?
If comparing two date/times, I would suggest looking at joda or perhaps date4j. Using joda, one could look into using interval between two dates:
Interval interval = new Interval(previousTime, new Instant());
where previous time would be the time you mentioned
You can do something like this:
try {
// reading text...
Scanner scan = new Scanner( new FileInputStream( new File( "path to your file here..." ) ) );
String dateString = scan.nextLine();
// creating a formatter.
// to understand the format, take a look here: http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
// EEE: Day name of week with 3 chars
// MMM: Month name of the year with 3 chars
// dd: day of month with 2 chars
// HH: hour of the day (0 to 23) with 2 chars
// mm: minute of the hour with 2 chars
// ss: second of the minute with 2 chars
// zzz: Timezone with 3 chars
// yyyy: year with 4 chars
DateFormat df = new SimpleDateFormat( "EEE MMM dd HH:mm:ss zzz yyyy", Locale.US );
// parsing the date (using the format above, that matches with your date string)
Date date = df.parse( dateString );
// now!
Date now = new Date();
// gets the differente between the parsed date and the now date in milliseconds
long diffInMilliseconds = now.getTime() - date.getTime();
if ( diffInMilliseconds < 0 ) {
System.out.println( "the date that was read is in the future!" );
} else {
// calculating the difference in hours
// one hour have: 60 minutes or 3600 seconds or 3600000 milliseconds
double diffInHours = diffInMilliseconds / 3600000D;
System.out.printf( "%.2f hours have passed!", diffInHours );
}
} catch ( FileNotFoundException | ParseException exc ) {
exc.printStackTrace();
}
I would suggest storing your information as a java.util.Calendar which has a compareTo ()function.
If you want to compare now to current time, you can use System.getCurrentTimeMillis() to get the current time.
Define A Day
Do you really mean one day or 24-hours? Because of Daylight Saving Time nonsense, a day can vary in length such as 23 or 25 hours in the United States.
Avoid 3-Letter Time Zone Codes
That String format is a terrible representation of a date-time. It is difficult to parse. It uses a 3-letter time zone code, and such codes are neither standardized nor unique. If possible, choose another format. The obvious choice is ISO 8601, for example: 2014-07-08T04:17:01Z.
Use proper time zone names.
Avoid j.u.Date & .Calendar
The java.util.Date and .Calendar classes bundled with Java are notoriously troublesome. Avoid them.
Instead use either the venerable Joda-Time library or the new java.time package bundled in Java 8 (and inspired on Joda-Time).
Joda-Time
Here is some example code in Joda-Time.
Get the current moment.
DateTime now = DateTime.now();
Parse the input string.
String input = "Sat Jul 21 23:31:55 EDT 2012";
DateTime formatter = DateTimeFormat.forPattern( "EEE MMM dd HH:mm:ss zzz yyyy" ).with Locale( java.util.Locale.ENGLISH );
DateTime target = formatter.parseDateTime( input );
Calculate 24 hours (or next day).
DateTime twentyFourHoursLater = target.plusHours( 24 );
Test if current moment happened after.
boolean expired = now.isAfter( twentyFourHoursLater );
Or, if you want next day rather than 24-hours, use plusDays rather than plusHours. If necessary, adjust to desired time zone. Time zone is crucial as it defines the day/date and applies rules for anomalies such as Daylight Saving Time.
DateTime targetAdjusted = target.withZone( DateTimeZone.forID( "Europe/Paris" ) );
…
DateTime aDayLater = targetAdjusted.plusDays( 1 ); // Go to next day, accounting for DST etc.
boolean expired = now.isAfter( aDayLater ); // Test if current moment happened after.
Related
Getting an Unparseable date error while calculating difference between Current date/time and Start date/time for an user.
Error: java.text.ParseException: Unparseable date: "09/11/20 00:00:00 AM CDT" at java.base/java.text.DateFormat.parse(DateFormat.java:395)
I get this error at line no.8, which is
String output2 = sdf1.format((sdf1.parse(startDate)).getTime());
'dateDifference' is a library used to calculate the difference between the current date/time and the start date/time of an user.
if(link.getAttribute("lastLogonTimeStamp")== null){
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
Calendar cur_time = Calendar.getInstance();
cur_time.setTime(new Date());
String output = sdf.format(cur_time.getTime());
System.out.println(" +++++ Output +++++" + output);
SimpleDateFormat sdf1 = new SimpleDateFormat("MM/dd/yy HH:mm:ss a zzz");
String output2 = sdf1.format((sdf1.parse(startDate)).getTime());
System.out.println(" +++++ Start Date +++++" + output2);
int diff = dateDifference(output2);
System.out.println(" +++++ Difference +++++" + diff);
if(diff>0){
System.out.println("Start Date is not a Future Date :" + startDate);
bw.write(id.getName()+","+ntID+","+id.getFirstname() +" "+id.getLastname() +","+id.getEmail()+ "," + id.getAttribute("empType")+ "," +lastLoginDt+ ","+mgrName+","+(String)id.getAttribute("startDate")+","+(String)id.getAttribute("title")+"\n");
count++;
}
}
tl;dr
I would not accept such a poor input string into my own app. But if you insist, you can try to parse ambiguous input such as CDT but this is a guessing game that may fail depending on the input.
ZonedDateTime.parse(
"09/11/20 00:00:00 AM CDT" ,
DateTimeFormatter.ofPattern( "MM/dd/uu HH:mm:ss a z" )
)
Parsing
CDT is not a real time zone. It is a localized indicator of whether Daylight Saving Time (DST) is effect.
Do not use localized formats for data exchange. Use localized values only for presentation to the user. For data exchange, use only ISO 8601 standard formats. The standard was invented for just that purpose, data exchange. The java.time classes use the standard formats by default when parsing/generating strings, so no need to specify formatting patterns.
Do not use Calendar and SimpleDateFormat classes. These terrible date-time classes are now legacy, years ago supplanted by the modern java.time classes defined in JSR 310. Search to learn more as this has been covered many many times already on Stack Overflow.
You can ask DateTimeFormatter class to guess what CDT might mean. But those pseudo-zone values are not standardized, and are not even unique! For example CST might mean "China Standard Time" or might mean "Central Standard Time" (in North America).
I recommend against accepting such poor inputs as yours, as playing guessing games in your code makes for unreliable apps. But if you insist:
String input = "09/11/20 00:00:00 AM CDT";
DateTimeFormatter f = DateTimeFormatter.ofPattern( "MM/dd/uu HH:mm:ss a z" );
ZonedDateTime zdt = ZonedDateTime.parse( input , f );
zdt.toString() = 2020-09-11T00:00-05:00[America/Chicago]
The text generated by ZonedDateTime#toString is actually an extension to the ISO 8601 standard format, appending the name of the zone in square brackets.
Calculating elapsed time
Apparently you want to calculate the amount of time elapsed between the moment represented by your input and the current moment.
To calculate elapsed time in terms of hours-minutes-seconds, use Duration while capturing the current moment as seen in UTC (an offset from UTC of zero hours-minutes-seconds).
Duration elapsed = Duration.between( zdt.toInstant() , Instant.now() ) ;
To calculate elapsed time in terms of years-months-days, use Period. Access the time zone contained in our ZonedDateTime to get the same timeframe.
Period elapsed = Period.between( zdt , ZonedDateTime.now( zdt.getZone() ) ;
I have rewritten the code in the below format and that worked.
if(lastLogon == null || lastLogon.equalsIgnoreCase("never")){
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
Calendar cur_time = Calendar.getInstance();
cur_time.setTime(new Date());
String output = sdf.format(cur_time.getTime());
SimpleDateFormat dateParser = new SimpleDateFormat("MM/dd/yy HH:mm:ss a zzz");
Date date = dateParser.parse(startDate);
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyyMMddHHmmss");
String output2 = dateFormatter.format(date);
int diff = dateDifference(output2);
if(diff>0){}
I have time stamp in format 2017-18-08 11:45:30.345.
I want to convert it to epoch time, so I am doing below:
String timeDateStr = "2017-18-08 11:45:30.345";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-dd-MM HH:mm:ss.SSS");
ZonedDateTime zdt = ZonedDateTime.parse(timeDateStr, dtf);
System.out.println(zdt.toInstant().toEpochMilli());
I am getting below error:
java.time.format.DateTimeParseException: Text '2017-18-08 11:45:30.345' could not be parsed: Unable to obtain ZonedDateTime from TemporalAccessor
I also tried different formats but still getting errors.
Note: originally the question had the input 2017-18-08 12:60:30.345 (with 60 in the minutes field), then it was edited (the time changed from 12:60 to 11:45), but I decided to keep this answer discussing about the original input (12:60), as it also works for the edited version (11:45).
ZonedDateTime needs a timezone or offset, but the input String doesn't have it (it has only date and time).
There are also another details in the input:
the minute value is 60, which is not accepted: the valid values are from 0 to 59 (actually there's a way to accept this, see "Lenient parsing" below)
the hh is the clock-hour-of-am-pm field, so it also needs the AM/PM designator to be fully resolved. As you don't have it, you should use the HH pattern instead
So the pattern must be yyyy-dd-MM HH:mm:ss.SSS, the input can't have 60 as the minutes value (unless you use lenient parsing, which I'll explain below) and you can't direclty parse it to a ZonedDateTime because it doesn't have a timezone/offset designator.
One alternative is to parse it to a LocalDateTime and then define in which timezone/offset this date is. In the example below, I'm assuming it's in UTC:
// change 60 minutes to 59 (otherwise it doesn't work)
String timeDateStr = "2017-18-08 12:59:30.345";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-dd-MM HH:mm:ss.SSS");
// parse to LocalDateTime
LocalDateTime dt = LocalDateTime.parse(timeDateStr, dtf);
// assume the LocalDateTime is in UTC
Instant instant = dt.toInstant(ZoneOffset.UTC);
System.out.println(instant.toEpochMilli());
This will output:
1503061170345
Which is the equivalent of 2017-18-08 12:59:30.345 in UTC.
If you want the date in another timezone, you can use the ZoneId class:
// get the LocalDateTime in some timezone
ZonedDateTime z = dt.atZone(ZoneId.of("Europe/London"));
System.out.println(z.toInstant().toEpochMilli());
The output is:
1503057570345
Note that the result is different, because the same local date/time represents a different Instant in each timezone (in each part of the world, the local date/time 2017-18-08 12:59:30.345 happened in a different instant).
Also note that 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.
There's also the option to convert the LocalDateTime to an offset (like -05:00 or +03:00):
// get the LocalDateTime in +03:00 offset
System.out.println(dt.toInstant(ZoneOffset.ofHours(3)).toEpochMilli());
The output will be equivalent to the local date/time in the offset +03:00 (3 hours ahead of UTC):
1503050370345
Lenient parsing
As #MenoHochschild reminded me in the comments, you can use lenient parsing to accept 60 in the minutes field (using the java.time.format.ResolverStyle class):
String timeDateStr = "2017-18-08 12:60:30.345";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-dd-MM HH:mm:ss.SSS")
// use lenient parsing
.withResolverStyle(ResolverStyle.LENIENT);
// parse to LocalDateTime
LocalDateTime dt = LocalDateTime.parse(timeDateStr, dtf);
In this case, 60 minutes are adjusted to the next hour, and the LocalDateTime will be:
2017-08-18T13:00:30.345
Daylight Saving Time
If you decide to use UTC or a fixed offset (using ZoneOffset class), you can ignore this section.
But if you decide to use a timezone (with ZoneId class), you must also take care of DST (Daylight Saving Time) issues. I'm gonna use the timezone I live in as example (America/Sao_Paulo).
In São Paulo, DST starts at October 15th 2017: at midnight, clocks shift 1 hour forward from midnight to 1 AM. So all local times between 00:00 and 00:59 don't exist in this timezone. If I create a local date in this interval, it's adjusted to the next valid moment:
ZoneId zone = ZoneId.of("America/Sao_Paulo");
// October 15th 2017 at midnight, DST starts in Sao Paulo
LocalDateTime d = LocalDateTime.of(2017, 10, 15, 0, 0, 0, 0);
ZonedDateTime z = d.atZone(zone);
System.out.println(z);// adjusted to 2017-10-15T01:00-02:00[America/Sao_Paulo]
When DST ends: in February 18th 2018 at midnight, clocks shift back 1 hour, from midnight to 23 PM of 17th. So all local times from 23:00 to 23:59 exist twice (in DST and in non-DST), and you must decide which one you want:
// February 18th 2018 at midnight, DST ends in Sao Paulo
// local times from 23:00 to 23:59 at 17th exist twice
LocalDateTime d = LocalDateTime.of(2018, 2, 17, 23, 0, 0, 0);
// by default, it gets the offset before DST ends
ZonedDateTime beforeDST = d.atZone(zone);
System.out.println(beforeDST); // before DST end: 2018-02-17T23:00-02:00[America/Sao_Paulo]
// get the offset after DST ends
ZonedDateTime afterDST = beforeDST.withLaterOffsetAtOverlap();
System.out.println(afterDST); // after DST end: 2018-02-17T23:00-03:00[America/Sao_Paulo]
Note that the dates before and after DST ends have different offsets (-02:00 and -03:00). This affects the value of epochMilli.
You must check when DST starts and ends in the timezone you choose and check the adjustments accordingly.
Corrected your code regarding yyyy-dd-MM. Also minute value could be 1-59 not 60. You provided 60. This is another simple way to solve the issue. Simply use DateFormat class.
String timeDateStr = "2017-18-08 12:59:30.345";
DateFormat df = new SimpleDateFormat("yyyy-dd-MM hh:mm:ss.SSS", Locale.ENGLISH);
try {
Date d = df.parse(timeDateStr);
System.out.println(d.toInstant().toEpochMilli());
} catch (ParseException e) {
e.printStackTrace();
}
Just i had made little bit change in nagendra547's answer
Please reffer to below code:-
String timeDateStr = "2017-18-08 12:59:30.345";
DateFormat df = new SimpleDateFormat("yyyy-dd-mm hh:mm:ss.SSS", Locale.ENGLISH);
try {
Date d = df.parse(timeDateStr);
System.out.println(d.toInstant().toEpochMilli());
} catch (ParseException e) {
e.printStackTrace();
}
Your code will fail for below 3 reasons.
Your date string (2017-18-08 12:60:30.345), doesn't match with the Formatter you used. It should be yyyy-MM-dd HH:mm:ss.SSS instead of yyyy-dd-MM hh:mm:ss.SSS
the range of minutes is (0-59), 60 doesn't come in this range.
Even if you have corrected code based above point it won't run for ZonedDateTime. So you would need to create a LocalDateTime before and then pass a ZoneId to it.
The code should look like below:
String timeDateStr = "2017-18-08 12:59:30.345";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-dd-MM HH:mm:ss.SSS");
LocalDateTime date = LocalDateTime.parse(timeDateStr, dtf);
ZonedDateTime zdt = date.atZone(ZoneId.of("Europe/London"));
System.out.println(zdt.toInstant().toEpochMilli());
I am converting string to date object i have string like
2017/3/30. when i parse into date object it gives
sunday web, GMT 03 00:00:00 GMT+05:00 2019
Code is
String dob = "2017/3/30";
SimpleDateFormat format = new SimpleDateFormat("yyyy/dd/MM");
try {
startDate = format.parse(dob);
endDate = format.parse(formattedDate);
} catch (ParseException e) {
e.printStackTrace();
}
I need same formate in date object not string .
You need to format it again after parsing
new SimpleDateFormat("yyyy/dd/MM").format(date);
The 'format' method returns a String object from a Date object according to the pattern you specified. What you need is the .parse(String) method, which returns a Date from a String.
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/dd/MM");
String yourDate = "2017/03/30";
try {
Date startDate = sdf.parse(yourDate);
} catch (ParseException e) {
e.printStackTrace();
}
Note that you have to comply with the given pattern, your date must be "2017/03/30". Hope this helps.
I think your problem is that your actual date format, 2017/3/30, does not agree with the format string you are giving to your SimpleDateFormat, yyyy/dd/MM. The first has the month in the middle and the day-of month last; the latter has got them the other way around. Therefore the Date you get from dob is the 3rd of June, 2019 (I think this is what you were trying to say, it wasn’t 100 % clear). SimpleDateFormat is understanding your dob as the 3rd day of the 30th month of 2017; when there are only 12 months in a year it just continues counting months into 2018 and 2019. It is quite lenient about the values supplied.
You just need to decide on the order of day, month and year. Your question (with the title) mentions 3 different orders, dd/mm/yyyy, 2017/3/30 and yyyy/dd/MM. Once you’re being consistent, your problems will be solved, I expect.
In most cases we don’t want to let bugs like this one slip through unnoticed. The solution to this is
format.setLenient(false);
After this call, your date format will no longer accept 30 as a month number, and will report your error back to you so you know and can correct it (and may not need to ask on Stack Overflow :-)
Stop using troublesome old date-time classes that are now legacy, supplanted by the java.time classes.
For a date-only value, parse as LocalDate.
String input = "2017/3/30";
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu/m/d" );
LocalDate ld = LocalDate.parse( input , f );
To assign the first moment of the day, specify a time zone.
ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = ld.atStartOfDay( z );
To generate strings representing these values use DateTimeFormatter. This has been covered hundreds of times already. So search Stack Overflow for more examples and more discussions.
String output = ld.format( f );
I'm trying to create a simple Alarm Clock, but I stumbled upon a problem that I can't seem to fix. I'm trying to parse a string to a date so I can get the difference between the current time and the time to set off the alarm.
Here's my code to parse the time:
SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss");
sdf.setTimeZone(getTimezone());
Date date = sdf.parse(args[0]);
Here's my getTimezone() method:
public static TimeZone getTimezone() {
Calendar cal = Calendar.getInstance();
long milliDiff = cal.get(Calendar.ZONE_OFFSET);
String [] ids = TimeZone.getAvailableIDs();
String name = null;
for (String id : ids) {
TimeZone tz = TimeZone.getTimeZone(id);
if (tz.getRawOffset() == milliDiff) {
// Found a match.
name = id;
break;
}
}
return TimeZone.getTimeZone(name);
}
And here's my code for figuring out the difference:
long diff = date.getTime() - System.currentTimeMillis();
So my problem is that the date.getTime() returns 79680000, while System.currentTimeMillis() returns 1473538047978 (This is of course different every time, but for some odd reason, date.getTime() is not).
Which means that I get a negative number when trying to figure out the difference, and therefore I cannot use it.
EDIT: After a little bit of debugging, I realised that it has to do with the year, month and day not being set, however I do not know how to get those.
You did notice that date.getTime() returns 79680000 which is 22 hours and 20 minutes after 1 January 1970. The problem is (as you noticed) that you did not parse year, month and day.
You can do it by:
SimpleDateFormat sdf = new SimpleDateFormat("DD/MM/YYYY hh:mm:ss");
Example input 20/04/2016 20:20:0 returns time as Mon Jan 04 20:20:00 CET 2016 (don't look at the timezone). It is 1451935200000 miliseconds after 1 January 1970.
Note: change string to match your format requirements (the syntax is self-explanatory).
The accepted answer by Ronin is correct. You are trying to put a time-of-day value into a date-time type.
java.time
Also, you are using troublesome old legacy date-time classes. Now supplanted by the java.time classes.
For a time-of-day value without a date and without a time zone, use LocalTime.
LocalTime alarmTime = LocalTime.parse( "12:34" );
Getting current time-of-day requires a time zone.
ZoneId z = ZoneId.of( "America/Montreal" );
LocalTime now = LocalTime.now( z );
But since we are setting an alarm, we care about the date too.
ZonedDateTime now = ZonedDateTime.now( z );
ZonedDateTime alarm = null;
if ( now.toLocalTime().isBefore( alarmTime ) ) {
alarm = ZonedDateTime.of( now.toLocalDate() , alarmTime , z );
} else {. // Else too late for today, so set alarm for tomorrow.
alarm = ZonedDateTime.of( now.toLocalDate().plusDays( 1 ) , alarmTime , z );
}
To calculate the elapsed time until the alarm, use the Duration class.
Duration untilAlarm = Duration.between( now , alarm );
You can interrogate the duration for a total number of milliseconds. But know that java.time classes are capable of handling nanoseconds.
long millis = untilAlarm.toMillis();
Updated.
You are using only time without a date with you date object in code (parses only time). If you add there date to you time, your date should be comparable to your System.getCurrentTimeMillis() call. And if you subtracting current millis from date in the past, you will have negative numbers. I prefer this convertion (date2 is after date1):
long diffInMillies = date2.getTime() - date1.getTime();
return TimeUnit.convert(diffInMillies, TimeUnit.MILLISECONDS);
In JAVA, how can I make sure that all dates are returned as GMT dates ?
For example, even if I try to force a DateFormat with GMT locale, it's applying some sort of logic that retrieves a BST date.
public static void main(String[] args) throws ParseException {
DateFormat dd = new SimpleDateFormat("MMM dd HH:mm:ss zzz yyyy");
dd.setTimeZone(TimeZone.getTimeZone("GMT"));
Date parse = dd.parse("Out 29 23:00:00 GMT 2011");
Date parse2 = dd.parse("Out 30 23:00:00 GMT 2011");
System.out.println(parse); // Prints "Sun Oct 30 00:00:00 BST 2011"
System.out.println(parse2); // Prints "Sun Oct 30 23:00:00 GMT 2011"
System.out.println(Locale.getDefault()); // Prints "en_US"
System.out.println(TimeZone.getDefault().getID()); // Prints "Europe/London"
}
Where is the BST coming from ? Is it related to daylight saving times ? TimeZone class says otherwwise.
System.out.println(TimeZone.getTimeZone("GMT").inDaylightTime(parse)); // Prints "false"
System.out.println(TimeZone.getTimeZone("GMT").inDaylightTime(parse2)); // Prints "false"
The default system locale is en_US.
Edit: Based on Basil Bourque's response, I can get both prints to GMT dates, if I change the default time zone to GMT:
TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
Mystery
Are you sure your comments on both System.out.println lines are correct? I expect output from both lines to have the same time zone, either BST or GMT.
If you are certain those are correct, please post a complete example of working code. Also document your default locale and time zone.
Fully Working Example
Here is my version of your code transformed into a fully working example. I deduce from the BST and out that this is Portuguese Brazil locale.
java.util.Locale.setDefault( new Locale.Builder().setLanguage( "pt" ).setRegion( "BR" ).build() ); // **HACK* Think twice before ever setting the default of your JVM’s locale or time zone. Generally a bad idea.
java.text.DateFormat dd = new java.text.SimpleDateFormat( "MMM dd HH:mm:ss zzz yyyy" );
dd.setTimeZone( java.util.TimeZone.getTimeZone( "GMT" ) );
Date parse = null;
Date parse2 = null;
try {
parse = dd.parse( "Out 29 23:00:00 GMT 2011" );
parse2 = dd.parse( "Out 30 23:00:00 GMT 2011" );
} catch ( ParseException ex ) {
Logger.getLogger( JodaTimeWork.class.getName() ).log( Level.SEVERE , null , ex );
}
System.out.println( parse );
System.out.println( parse2 );
My output when running on a US locale and America/Los_Angeles time zone, thus the PDT time zone.
Sat Oct 29 16:00:00 PDT 2011
Sun Oct 30 16:00:00 PDT 2011
No Time Zone On A Date Object
Be aware that a java.util.Date object has no time zone assigned†. Confusingly, the toString method implementation on that class applies the JVM’s current default time zone. So it seems like the Date object has a time zone, but it does not.
As the correct comment by GriffeyDog said, the DateFormat object has a time zone but the Date object does not.
So I expect both of your System.out.println lines to emit text with the same time zone, as I said up top.
Joda-Time | java.time
This confusing handling of time zones is one of many reasons to avoid java.util.Date/.Calendar & SimpleTextFormat. Those in the know use either the Joda-Time library or the new java.time package built into Java 8. The java.time package was inspired by Joda-Time but is re-architected; each has its strengths and weaknesses.
Example in Joda-Time
Here is an example in Joda-Time 2.7.
Time Zone on DateTime
A DateTime object in Joda-Time knows its own assigned time zone, unlike a java.util.Date object.
Incorrect Localization
Your input data’s use of an uppercase O for Out appears to be incorrect for Portuguese convention. My example corrects that to be lowercase. Joda-Time rejects the uppercase as invalid.
Code
String input1 = "out 29 23:00:00 GMT 2011";
String input2 = "out 30 23:00:00 GMT 2011";
Locale locale_pt_BR = new Locale.Builder().setLanguage( "pt" ).setRegion( "BR" ).build(); //
DateTimeFormatter formatter = DateTimeFormat.forPattern( "MMM dd HH:mm:ss 'GMT' yyyy" ).withLocale( locale_pt_BR ).withZone( DateTimeZone.UTC );
DateTime dateTime1 = null;
DateTime dateTime2 = null;
DateTime dateTime1_Sao_Paulo = null;
DateTime dateTime2_Sao_Paulo = null;
try {
dateTime1 = formatter.parseDateTime( input1 );
dateTime2 = formatter.parseDateTime( input2 );
// Adjust to "America/Sao_Paulo" time zone.
DateTimeZone zone_Sao_Paulo = DateTimeZone.forID( "America/Sao_Paulo" );
dateTime1_Sao_Paulo = dateTime1.withZone( zone_Sao_Paulo );
dateTime2_Sao_Paulo = dateTime2.withZone( zone_Sao_Paulo );
} catch ( IllegalArgumentException e ) {
// … Handle exception.
System.out.println( "ERROR - Unexpected input for parsing into a date-time object." );
}
Dump to console.
System.out.println( "dateTime1 : " + dateTime1 );
System.out.println( "dateTime2 : " + dateTime2 );
System.out.println( "Adjusted to America/Sao_Paulo: " + dateTime1_Sao_Paulo + " & " + dateTime2_Sao_Paulo );
When run.
dateTime1 : 2011-10-29T23:00:00.000Z
dateTime2 : 2011-10-30T23:00:00.000Z
Adjusted to America/Sao_Paulo: 2011-10-29T21:00:00.000-02:00 & 2011-10-30T21:00:00.000-02:00
ISO 8601
If you have any control or influence on the format of your input data, I strongly suggest changing to the standard ISO 8601 format.
Example: 2015-02-15T19:39:11Z.
Time Zone
Avoid the 3 or 4 letter codes for time zones. They are neither standardized nor unique. BST for example can be:
British Summer Time (outdated as of 1971 but still tops in Google hits)
Brazil Standard Time
Bangladesh Standard Time
Use proper time zone names. Example: America/Sao_Paulo.
3-4 Letter Codes Refused By Joda-Time
Because of the frequent duplicate values, it is impossible to responsibly parse such values. So Joda-Time refuses to try.
Note in the example code above how I hard-coded the expected GMT value. See the single-quote marks (APOSTROPHE) around the "GMT" letters. That tells Joda-Time to expect and ignore that string while parsing.
This has a crucial consequence: With no identified time zone or offset-from-UTC, Joda-Time does not know how to interpret the date-time when parsing the string. We set the formatter to a time zone by which to interpret the string with no time zone or offset. If the string did have an offset, setting a time zone on the formatter has a different behavior: after parsing, the formatter adjusts the value to that time zone.
† Even more confusing, the java.util.Date actually does have a time zone, but buried deep within its implementation. That time zone is ignored for most practical purposes. So as shorthand, we say a j.u.Date has no time zone (effectively acts as if in UTC).