I tried to create an timestamp to Date and Date to timestamp converter in java. the converter logic works perfectly and I displayed it on a console window. But this works not correctly.
If I type this timestamp into my console window:
1449946800000 (I get this timestamp from my calendar web plugin)
Date : 13.10.2016 20:00:00 (Timezone "Europe/Berlin ) = 1476381600000
First time I call a mehtod which required the timestamp format like above.
LongStamp = LongStamp/1000;
logic.convertedTime(LongStamp);
} else {
.....
}
If match, the method logic.convertedTime(xx) is calling. ( See class convertLogic)
Here is my code:
public class convertLogic {
/** TimeZone-Support**/
private static final String TIMEZONEBERLIN = "Europe/Berlin";
/**
* convertedTime: <br>
* input timestamp to convert into date <br>
* <strong>...</strong>
* #param timestamp
*/
public void convertedTime(long timestamp) {
TimeZone timeZoneBerlin = TimeZone.getTimeZone(TIMEZONEBERLIN);
// System.out.println(timeZoneBerlin.getDisplayName());
// System.out.println(timeZoneBerlin.getID());
// System.out.println(timeZoneBerlin.getOffset(System.currentTimeMillis()));
Calendar myDate = GregorianCalendar.getInstance();
myDate.setTimeZone(timeZoneBerlin);
myDate.setTimeInMillis(timestamp * 1000);
int month = myDate.get(Calendar.MONTH) + 1;
int second = Integer.parseInt(leadingZero(myDate.get(Calendar.SECOND)));
System.out.println("Datum: " + myDate.get(Calendar.DAY_OF_MONTH) + "." + month + "." + myDate.get(Calendar.YEAR)
+ " " + myDate.get(Calendar.HOUR_OF_DAY) + ":" + myDate.get(Calendar.MINUTE) + ":"
+ second);
}
/**
* leadingZero for 2 digit values
*
* #param value
* #return String
*/
private static String leadingZero(int value) {
int testValue = value;
if (testValue < 10) {
return "0" + value;
} else {
return value + "";
}
}
And I get following output:
Datum: 13.10.2016 20:0:0
But I want or I need all zeros from the Hour,Minutes and seconds like this :
13.10.2016 20:00:00
Does anybody know an solution?
Thanks in advance!
Fix: Call your leadingZero method
After adding a leading zero you effectively remove it.
After padding with a leading zero, you call Integer.parseInt. That call generates a number, an int. The default format used when converting that to a String has no leading zero.
Change the data type of second to String.
Likewise, pass the result of myDate.get(Calendar.HOUR_OF_DAY) to your leadingZero method.
Strange results
I do not understand your input and results. If 1449946800000 is a count of milliseconds from the epoch of first moment of 1970 UTC, that is a date-time in 2015 not 2016:
2015-12-12T19:00:00Z
2015-12-12T20:00+01:00[Europe/Berlin]
java.time
You are working too hard. Use a date-time framework for this work.
The java.time framework is built into Java 8 and later. These classes supplant the old troublesome date-time classes such as java.util.Date, .Calendar, & java.text.SimpleDateFormat.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations.
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP.
Example code
First translate your count-from-epoch into an Instant object representing a moment on the timeline in UTC with a resolution up to nanoseconds.
long input = 1_449_946_800_000L;
Instant instant = Instant.ofEpochMilli ( input );
Apply a time zone, Europe/Berlin. A ZoneId represents the time zone. We use that to generate a ZonedDateTime object.
ZoneId zoneId = ZoneId.of ( "Europe/Berlin" );
ZonedDateTime zdt = ZonedDateTime.ofInstant ( instant , zoneId );
Create a String to represent the value of our ZonedDateTime object.
No need to define a formatting pattern. The DateTimeFormatter class can automatically localize a date-time representation to a human language and cultural norms defined by a Locale. Your desired format is already known to be the medium-length format commonly used in Germany.
Understand that a time zone and a Locale are distinct and separate. One adjusts the meaning of the date-time to a wall-clock time of some geographic area on the globe. The other translates names of day or month, and determines comma versus period, and other such issues.
Locale locale = Locale.GERMANY;
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime ( FormatStyle.MEDIUM ).withLocale ( locale );
String output = zdt.format ( formatter );
Dump to console.
System.out.println ( "input: " + input + " | instant: " + instant + " | zdt: " + zdt + " | output: " + output );
input: 1449946800000 | instant: 2015-12-12T19:00:00Z | zdt: 2015-12-12T20:00+01:00[Europe/Berlin] | output: 12.12.2015 20:00:00
DateFormat might be your friend to simplify the code (or DateTimeFormatter in case of Java 8).
Related
Given a ISO string like this
String dateTime = "2016-07-11T16:50:22.00+05:00";
Is there a way to find an offset is present in the specific string or not using joda?
This is what the code i have done so far, to get an offset if one is present
public static String getDateTimeWithTimeZoneOffset(String dateTimeString)
{
DateTimeFormatter df = ISODateTimeFormat.dateTimeParser().withOffsetParsed();
DateTime nDt = df.parseDateTime(dateTimeString);
DateTimeFormatter dateFormatterWithoutMillis = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss");
return dateFormatterWithoutMillis.print(nDt) + SPACE + nDt.getZone();
}
the above code gives the below output
2016-07-11T16:50:22 +05:00
but when I have a string without an offset, like this one below
2016-07-11T16:50:22
The same code takes in a default time zone and prints like this
2016-07-11T16:50:22 America/Chicago
is there anyway i can check if an offset is present in the string or not, if not throw an exception?
java.time
The Joda-Time development team advises migration to java.time classes:
Joda-Time is the de facto standard date and time library for Java prior to Java SE 8. Users are now asked to migrate to java.time (JSR-310).
the java.time framework built into Java 8 and later. These classes supplant the old troublesome date-time classes such as java.util.Date as well as the highly successful 3rd-party Joda-Time library. See Oracle Tutorial. Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP.
OffsetDateTime
The OffsetDateTime class represents a moment on the timeline with an assigned offset-from-UTC. The offset is represented by the ZoneOffset class.
LocalDateTime
If your input string lacks any offset or time zone info, it is considered to be a “local” date-time. That means it is not a particular moment on the timeline, but rather a rough idea about a possible moment. Has no real meaning until you apply an offset or time zone.
The LocalDateTime class handles this kind of value.
ISO 8601
Your input string happens to comply with the ISO 8601 standard for date-time text formats.
The java.time classes use these standard formats by default when parsing/generating strings that represent date-time values. So, you can directly parse the input string without defining a formatting pattern.
Example code
The strategy here is to try parsing as if the input string includes an offset. If not, an exception (DateTimeParseException) is thrown. In that case, we try parsing again but as a LocalDateTime value. If that second attempt throws a parsing exception, then the input is completely unexpected.
Some coding-fundamentalists will protest this use of nested exception testing. While I understand their concerns as this approach can be abused, in this particular kind of situation I maintain nested exception testing is acceptable, logical, and clear.
String input = "2016-07-11T16:50:22.00"; // "2016-07-11T16:50:22.00+05:00";
Boolean hasOffset = null;
try {
OffsetDateTime odt = OffsetDateTime.parse ( input );
hasOffset = Boolean.TRUE;
ZoneOffset offset = odt.getOffset ();
System.out.println ( "input: " + input + " | hasOffset: " + hasOffset + " | odt: " + odt + " | offset: " + offset );
} catch ( java.time.format.DateTimeParseException e1 ) {
// Perhaps input lacks offset-from-UTC. Try parsing as a local date-time.
try {
LocalDateTime ldt = LocalDateTime.parse ( input );
hasOffset = Boolean.FALSE;
System.out.println ( "input: " + input + " | hasOffset: " + hasOffset + " | ldt: " + ldt );
} catch ( java.time.format.DateTimeParseException e2 ) {
System.out.println ( "ERROR - Unexpected format in the input string" ); // FIXME: Handle format exception.
}
}
When run with 2016-07-11T16:50:22.00+05:00.
input: 2016-07-11T16:50:22.00+05:00 | hasOffset: true | odt: 2016-07-11T16:50:22+05:00 | offset: +05:00
When run with 2016-07-11T16:50:22.00.
input: 2016-07-11T16:50:22.00 | hasOffset: false | ldt: 2016-07-11T16:50:22
Length testing
Of course you could always test the length of the input string. Given your example inputs, those with offsets will be longer than those without. Such length-testing can be brittle or error-prone if you have multiple kinds of input.
Try this:
String dateWithoutMillis = dateFormatterWithoutMillis.print(nDt) + SPACE + nDt.getZone();
if (dateWithoutMillis.contains("/") {
throw new InvalidDateStringException("NO OFFSET");
} else {
return dateWithoutMillis
}
And don't forget to add the Exception:
public static class InvalidDateStringException extends Exception {
public InvalidDateStringException(String message){
super(message);
}
}
You can do something like this:
if(dateTimeString.matches(".*(\\+|-)\\d{2}(:?\\d{2})?$")){
// has offset.
}
HERE is an example.
I'm trying to convert the date time string 10/10/2015 10:00:00 to the seconds since the unix epoch, which is 1444471200. However, weirdly I'm getting back the value 1444467600 which is actually 10/10/2015 09:00:00. Here's my code:
// using "joda-time" % "joda-time" % "2.9",
// "org.joda" % "joda-convert" % "1.8.1",
import org.joda.time.DateTime
import org.joda.time.format.DateTimeFormat
val dt = DateTime.parse(dateTimeString, DateTimeFormat.forPattern("MM/dd/yyyy HH:mm:ss"))
dt.getMillis / 1000
Where's this hour offset coming from and how can I get rid of it? My local timezone is GMT (which == UTC at the moment anyway)...
Apparently, it's not parsing with GMT/UTC. Just add that to your DateTimeFormat.
DateTimeFormat.forPattern("MM/dd/yyyy HH:mm:ss").withZoneUTC()
java.time
The Answer by Sotirios Delimanolis is correct. Here is the same kind of code for the java.time framework built into Java 8 and later, intended as the successor to Joda-Time.
First we define a formatter. Notice the call-chain, calling withZone to specify the zone by which we want the string parsed. This is not optional, as the input string lacks offset or time zone data.
Then we call the static parse method on ZonedDateTime to actually do the parsing.
Lastly we call the convenience method toEpochSecond to convert this date-time to the number of seconds from the epoch of 1970-01-01T00:00:00Z.
String input = "10/10/2015 10:00:00";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern ( "MM/dd/yyyy HH:mm:ss" ).withZone ( ZoneOffset.UTC );
ZonedDateTime zdt = ZonedDateTime.parse ( input , formatter );
long secondsFromEpoch = zdt.toEpochSecond ();
Dump to console.
System.out.println ( "input: " + input + " | zdt: " + zdt + " | secondsFromEpoch: " + secondsFromEpoch );
input: 10/10/2015 10:00:00 | zdt: 2015-10-10T10:00Z | secondsFromEpoch: 1444471200
I am trying to convert between a date printed out in an EST timezone into a date printed out in GMT/UTC
package com.stefano;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
public class MainEntry {
/**
* #param args
* #throws ParseException
*/
public static void main(String[] args) throws ParseException {
String dateTime = "1307011200"; //12:00PM 01 July 2013
System.out.println("Input -> " + dateTime);
SimpleDateFormat format = new SimpleDateFormat("yyMMddHHmm");
format.setTimeZone(TimeZone.getTimeZone("EST"));
Date date = format.parse(dateTime);
System.out.println("Intermediate -> " + date);
format.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println("Output -> " + format.format(date));
}
}
The output it gives is:
Input -> 1307011200
Intermediate -> Mon Jul 01 17:00:00 BST 2013
Output -> 1307011600
Even though the time difference between EST and GMT is always 5, it is somehow getting involved with BST.
I cannot use Joda-Time.
The javadoc of the SimpleDateFormat.parse(String) method refers to the parse(String, ParsePosition) method, that says:
This parsing operation uses the calendar to produce a Date. As a result, the calendar's date-time fields and the TimeZone value may have been overwritten, depending on subclass implementations. Any TimeZone value that has previously been set by a call to setTimeZone may need to be restored for further operations.
According to this you can't use this method to tell the SimpleDateFormat which timezone
the given date is in.
You can fix this method like this:
String dateTime = "1307011200"; // 12:00PM 01 July 2013
dateTime += " EST"; // append the timezone information to the input string
System.out.println("Input -> " + dateTime);
SimpleDateFormat format = new SimpleDateFormat("yyMMddHHmm z"); // tell the formatter to look for the timezone info
Date date = format.parse(dateTime);
System.out.println("Intermediate -> " + date);
format.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println("Output -> " + format.format(date));
This will also print the Date object using your local timezone, but it shows a way to parse the dateTime string using a given timezone.
The answer by zovits is correct.
US East Coast Offset
If by EST you mean the east coast of the United States (and parts of Canada), then your statement the time difference between EST and GMT is always 5 is incorrect. With Daylight Saving Time (DST), the offset may be -05:00 or -04:00. Indeed, your specified date-time does have DST in effect.
Avoid 3-4 Letter Time Zone Codes
Those three or four letter time zone codes are neither standardized nor unique. Avoid them. Use proper time zone names, most of which are continent+city.
Comparison To Joda-Time
For comparison, here is some Joda-Time example code. The java.util.Date & .Calendar classes bundled with Java are so notoriously troublesome that every Java programmer should move to either Joda-Time or the new Java 8 java.time package (inspired by Joda-Time, defined by JSR 310).
While a java.util.Date seems to have a time zone but actually does not, note that a Joda-Time DateTime does truly know its own assigned time zone.
Joda-Time uses the ISO 8601 standard for its defaults. You can use other formats as well, as seen with the Montréal example below.
Example Code
String input = "1307011200"; //12:00PM 01 July 2013
DateTimeFormatter formatterSmooshed = DateTimeFormat.forPattern( "yyMMddHHmm" );
DateTimeZone timeZoneNewYork = DateTimeZone.forID( "America/New_York" );
DateTime dateTimeNewYork = formatterSmooshed.withZone( timeZoneNewYork ).parseDateTime( input );
DateTime dateTimeUtc = dateTimeNewYork.withZone( DateTimeZone.UTC );
String outputMontréal = DateTimeFormat.forStyle( "FF" ).withLocale( Locale.CANADA_FRENCH ).print( dateTimeNewYork );
String outputSmooshed = formatterSmooshed.print( dateTimeNewYork ); // Expect same as input.
Dump to console…
System.out.println( "input: " + input );
System.out.println( "dateTimeNewYork: " + dateTimeNewYork );
System.out.println( "dateTimeUtc: " + dateTimeUtc );
System.out.println( "outputMontréal: " + outputMontréal );
System.out.println( "outputSmooshed: " + outputSmooshed );
When run…
input: 1307011200
dateTimeNewYork: 2013-07-01T12:00:00.000-04:00
dateTimeUtc: 2013-07-01T16:00:00.000Z
outputMontréal: lundi 1 juillet 2013 12 h 00 EDT
outputSmooshed: 1307011200
I have a Date Object which I need to convert to the logged in user's timezone. The problem is that the timezone is represented in our DB simply as a String value of GMT plus or minus the offset in hours. So for example "GMT" or "GMT-5" for New york time or "GMT+5".
How can I convert my Date Object to the User's time when all I have are String like "GMT-3" or "GMT+5"?
Thanks in advance for any help.
An example should help, but it seems a 1 character ISO 8601 time zone:
String myDate="2001-07-04T12:08:56GMT-3";
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'GMT'X");
if (myDate.indexOf("GMT-") >= myDate.length() -1 -4) {
myDate = myDate.replace("-","-0");
}
if (myDate.indexOf("GMT+") >= myDate.length() -1 -4) {
myDate = myDate.replace("+","+0");
}
System.out.println(format.parse(myDate));
it should work.
the yyyy-MM-dd'T'HH:mm:ss'GMT'X is compliant with iso8601 time zone
myDate = myDate.replace("-","-0"); adjusts the date to your format
Offset ≠ Time Zone
As Jon Skeet said in comment, a time zone is more than just an offset from UTC/GMT. Storing the offset hours (and minutes) is a less-than-optimal strategy for handling date-time in your database/storage.
Joda-Time
The java.util.Date & java.util.Calendar classes are notoriously troublesome. Avoid them. Use Joda-Time. Or, in Java 8, use the new java.time.* package, defined by JSR 310, and inspired by Joda-Time but re-architected.
We can create a DateTimeZone to represent the offset, but as noted this does not make a complete time zone logically.
We can pass a java.util.Date object directly to a Joda-Time DateTime constructor. Along with that we pass a DateTimeZone object. To go the other direction of conversion, call toDate on a DateTime object.
java.util.Date date = new java.util.Date(); // Retrieved from elsewhere. Faked here.
String offsetInput = "GMT-5";
int offsetHours = 0, offsetMinutes = 0;
offsetInput = offsetInput.replace( "GMT", "" ); // Delete 'GMT' characters.
String[] parts = offsetInput.split(":"); // About splitting a string: http://stackoverflow.com/q/3481828/642706
// Handle results of split.
if( parts.length == 0 ) {
// Add some error handling here
}
if ( parts.length >= 1 ) {
offsetHours = Integer.parseInt( parts[0] ); // Retrieve text of first number (zero-based index counting).
}
if ( parts.length >= 2 ) {
offsetMinutes = Integer.parseInt( parts[1] ); // Retrieve text of second number (zero-based index counting).
}
if( parts.length >= 3 ) {
// Add some error handling here
}
DateTimeZone partialTimeZoneWithOnlyOffset = DateTimeZone.forOffsetHoursMinutes( offsetHours, offsetMinutes );
DateTime dateTime = new DateTime( date, partialTimeZoneWithOnlyOffset );
Dump to console…
System.out.println( "date: " + date ); // BEWARE: JVM's default time zone applied in the implicit call to "toString" of a Date. Very misleading.
System.out.println( "partialTimeZoneWithOnlyOffset: " + partialTimeZoneWithOnlyOffset );
System.out.println( "dateTime: " + dateTime );
System.out.println( "dateTime with alternate formatting: " + DateTimeFormat.forStyle( "FF" ).withLocale( Locale.US ).print( dateTime ) );
When run…
date: Sat Feb 08 22:40:57 PST 2014
partialTimeZoneWithOnlyOffset: -05:00
dateTime: 2014-02-09T01:40:57.810-05:00
dateTime with alternate formatting: Sunday, February 9, 2014 1:40:57 AM -05:00
I have a date which must be localized.
Below code returns 5/1/12 19:06:34 but the result i want is 05/01/12 19:06:34
Could you please tell me how to manage this.
private String localizeDate(String date){ //Format is 2012-05-01 19:30:49
Locale loc = DataContextHolder.getDataContext().getLocale();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", loc);
Date parsed=null;
try {
parsed = formatter.parse(date);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, loc);
String localizedDate = df.format(parsed) + " " + date.substring(11, 13) + ":"
+ date.substring(14, 16) + ":"
+ date.substring(17, 19);
return localizedDate;
}
You can avoid leading zeros by reducing the number of consecutive pattern letters for that particular element. Multiple pattern letters in a row tell the date formatter that, at minimum, you want that many characters to express that value.
In your example, the following should resolve your problem.
new SimpleDateFormat("y-M-d H:m:s", loc);
Find more in the SimpleDateFormat documentation.
For clarity, see the following example.
SimpleDateFormat a = new SimpleDateFormat("yyyyy-MMMM-dddd HHH:mmmm:sssss");
SimpleDateFormat b = new SimpleDateFormat("y-M-d H:m:s");
System.out.println(a.format(new Date()));
// Prints 02012-June-0005 012:0027:00026
System.out.println(b.format(new Date()));
// Prints 12-6-5 12:27:26
Problems
You have multiple problems happening with your code.
Time-Zone
One problem is that you are localizing without handling time zone. The parsing will apply the JVM's default time zone. That means running on different computers with different time zone settings yields different results. Generally best to specify a time zone rather than rely on default.
Formatting, Not Localizing
Another problem is that if you are truly localizing, you would not be specifying the details of the format. You would let the locale drive the formatting, whatever is appropriate to that locale and to the user's own localization settings.
Avoid java.util.Date
Yet another problem is that you are using the java.util.Date class bundled with Java. That class, and its sibling java.util.Calendar, are notoriously troublesome. Avoid them. Use either the Joda-Time framework or the new java.time.* package in Java 8.
ISO 8601
Your input string is very close to the standard ISO 8601 format, like this: 2014-02-07T07:06:41+03:00. Your text is merely missing a T in the middle and a time zone offset.
The Joda-Time framework uses ISO 8601 by default. So replacing that space with a "T" lets you pass the string directly to a DateTime constructor. No need for a formatter and parsing, as the DateTime constructor will do that work for you automatically.
Note that including or omitting the time zone offset from the end of the string input changes the behavior of constructing a DateTime. Without an offset, the string is parsed as if it occurred at the specified time within the passed time zone (the 2nd argument, see code example below). On the other hand, if you do include an offset in your input, the string is parsed as if it occurred at the specified time in the offset's locality, and then adjusts the time to the passed time zone argument.
Joda-Time Example
Here is some example code in Joda-Time 2.3.
DateTimeZone timeZone = DateTimeZone.forID( "Europe/Istanbul" );
String inputOriginal = "2012-05-01 19:30:49";
String input = inputOriginal.replace( " ", "T" );
DateTime dateTime = new DateTime( input, timeZone );
// Or if your input is UTC/GMT (no time zone offset), pass a predefined DateTimeZone constant.
//DateTime dateTime = new DateTime( input, DateTimeZone.UTC );
We have our date-time value in hand. Now we proceed to generate formatted strings from that date-time. We do so by using Joda-Time’s Locale-sensitive formatting facility. Note that not only the format is localized, so is the text of the month and day names localized to appropriate language.
// Create a formatter from a two-character style pattern.
// The first character is the date style, and the second character is the time style.
// Specify a character of 'S' for short style, 'M' for medium, 'L' for long, and 'F' for full.
// A date or time may be ommitted by specifying a style character '-'.
java.util.Locale locale = new java.util.Locale( "tr", "TR" ); // Turkey chosen as an example.
String output_ShortShort = DateTimeFormat.forStyle( "SS" ).withLocale( locale ).print( dateTime );
String output_LongShort = DateTimeFormat.forStyle( "LS" ).withLocale( locale ).print( dateTime );
Dump to console…
System.out.println( "input: " + input );
System.out.println( "dateTime: " + dateTime );
System.out.println( "dateTime in UTC/GMT: " + dateTime.toDateTime( DateTimeZone.UTC ) );
System.out.println( "output_ShortShort: " + output_ShortShort );
System.out.println( "output_LongShort: " + output_LongShort );
When run…
input: 2012-05-01T19:30:49
dateTime: 2012-05-01T19:30:49.000+03:00
dateTime in UTC/GMT: 2012-05-01T16:30:49.000Z
output_ShortShort: 01.05.2012 19:30
output_LongShort: 01 Mayıs 2012 Salı 19:30
You need to choose the appropriate date formatter. Please read the documentation here:
http://docs.oracle.com/javase/6/docs/api/java/text/SimpleDateFormat.html