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
Related
I'm trying to format an Instant to a String using the new Java 8 Date and Time API and the following pattern:
Instant instant = ...;
String out = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(instant);
Using the code above I get an exception which complains about an unsupported field:
java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: YearOfEra
at java.time.Instant.getLong(Instant.java:608)
at java.time.format.DateTimePrintContext.getValue(DateTimePrintContext.java:298)
...
Time Zone
To format an Instant a time-zone is required. Without a time-zone, the formatter does not know how to convert the instant to human date-time fields, and therefore throws an exception.
The time-zone can be added directly to the formatter using withZone().
DateTimeFormatter formatter =
DateTimeFormatter.ofLocalizedDateTime( FormatStyle.SHORT )
.withLocale( Locale.UK )
.withZone( ZoneId.systemDefault() );
If you specifically want an ISO-8601 format with no explicit time-zone
(as the OP asked), with the time-zone implicitly UTC, you need
DateTimeFormatter.ISO_LOCAL_DATE_TIME.withZone(ZoneId.from(ZoneOffset.UTC))
Generating String
Now use that formatter to generate the String representation of your Instant.
Instant instant = Instant.now();
String output = formatter.format( instant );
Dump to console.
System.out.println("formatter: " + formatter + " with zone: " + formatter.getZone() + " and Locale: " + formatter.getLocale() );
System.out.println("instant: " + instant );
System.out.println("output: " + output );
When run.
formatter: Localized(SHORT,SHORT) with zone: US/Pacific and Locale: en_GB
instant: 2015-06-02T21:34:33.616Z
output: 02/06/15 14:34
public static void main(String[] args) {
DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
.withZone(ZoneId.systemDefault());
System.out.println(DATE_TIME_FORMATTER.format(new Date().toInstant()));
}
DateTimeFormatter.ISO_INSTANT.format(Instant.now())
This saves you from having to convert to UTC. However, some other language's time frameworks may not support the milliseconds so you should do
DateTimeFormatter.ISO_INSTANT.format(Instant.now().truncatedTo(ChronoUnit.SECONDS))
The Instant class doesn't contain Zone information, it only stores timestamp in milliseconds from UNIX epoch, i.e. 1 Jan 1070 from UTC.
So, formatter can't print a date because date always printed for concrete time zone.
You should set time zone to formatter and all will be fine, like this :
Instant instant = Instant.ofEpochMilli(92554380000L);
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT).withLocale(Locale.UK).withZone(ZoneOffset.UTC);
assert formatter.format(instant).equals("07/12/72 05:33");
assert instant.toString().equals("1972-12-07T05:33:00Z");
Instants are already in UTC and already have a default date format of yyyy-MM-dd. If you're happy with that and don't want to mess with time zones or formatting, you could also toString() it:
Instant instant = Instant.now();
instant.toString()
output: 2020-02-06T18:01:55.648475Z
Don't want the T and Z? (Z indicates this date is UTC. Z stands for "Zulu" aka "Zero hour offset" aka UTC):
instant.toString().replaceAll("[TZ]", " ")
output: 2020-02-06 18:01:55.663763
Want milliseconds instead of nanoseconds? (So you can plop it into a sql query):
instant.truncatedTo(ChronoUnit.MILLIS).toString().replaceAll("[TZ]", " ")
output: 2020-02-06 18:01:55.664
etc.
Or if you still want to use formatter created from pattern
you can just use LocalDateTime instead of Instant:
LocalDateTime datetime = LocalDateTime.now();
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(datetime)
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd");
String text = date.toString(formatter);
LocalDate date = LocalDate.parse(text, formatter);
I believe this might help, you may need to use some sort of localdate variation instead of instant
I have this code to add 1 hour or 1 day in date Java 8, but doesn´t work
String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
java.text.SimpleDateFormat format = new java.text.SimpleDateFormat(DATE_FORMAT);
Date parse = format.parse("2017-01-01 13:00:00");
LocalDateTime ldt = LocalDateTime.ofInstant(parse.toInstant(), ZoneId.systemDefault());
ldt.plusHours(1);
ZonedDateTime zdt = ldt.atZone(ZoneId.systemDefault());
Date te = Date.from(zdt.toInstant());
What´s wrong? The code shows: Sun Jan 01 13:00:00 BRST 2017
LocalDateTime is immutable and returns a new LocalDateTime when you call methods on it.
So you must call
ldt = ldt.plusHours(1);
Apart from the issue that you don't use the result of your date manipulation (ldt = ldt.plusHours(1)), you don't really need to go via a LocalDateTime for this operation.
I would simply use an OffsetDateTime since you don't care about time zones:
OffsetDateTime odt = parse.toInstant().atOffset(ZoneOffset.UTC);
odt = odt.plusDays(1).plusHours(1);
Date te = Date.from(odt.toInstant());
You could even stick to using Instants:
Instant input = parse.toInstant();
Date te = Date.from(input.plus(1, DAYS).plus(1, HOURS));
(with an import static java.time.temporal.ChronoUnit.*;)
tl;dr
LocalDateTime.parse( // Parse input string that lacks any indication of offset-from-UTC or time zone.
"2017-01-01 13:00:00".replace( " " , "T" ) // Convert to ISO 8601 standard format.
).atZone( // Assign a time zone to render a meaningful ZonedDateTime object, an actual point on the timeline.
ZoneId.systemDefault() // The Question uses default time zone. Beware that default can change at any moment during runtime. Better to specify an expected/desired time zone generally.
).plus(
Duration.ofDays( 1L ).plusHours( 1L ) // Add a span of time.
)
Details
Do not mix the troublesome old legacy classes Date and Calendar with the modern java.time classes. Use only java.time, avoiding the legacy classes.
The java.time classes use the ISO 8601 standard formats by default when parsing and generating strings. Convert your input string by replacing the SPACE in the middle with a T.
String input = "2017-01-01 13:00:00".replace( " " , "T" ) ;
LocalDateTime ldt = LocalDateTime.parse( input ) ;
ALocalDateTime does not represent an actual moment, not a point on the timeline. It has no real meaning until you assign a time zone.
ZoneId z = ZoneId.systemDefault() ; // I recommend specifying the desired/expected zone rather than relying on current default.
ZonedDateTime zdt = ldt.atZone( z ) ;
A Duration represents a span of time not attached to the timeline.
Duration d = Duration.ofDays( 1L ).plusHours( 1L ) ;
ZonedDateTime zdtLater = zdt.plus( d ) ;
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).
I am using java 8 time API to convert time in milliseconds to date and I am getting wrong day of week from that date.
here is my code -
long millis = 1406865600000L;
LocalDate localDate = LocalDate.ofEpochDay(millis/1000);
DayOfWeek dow = localDate.getDayOfWeek();
System.out.println(dow);
it prints out THURSDAY, while this is date Friday 1 AUG.
Please help.
LocalDate.ofEpochDay() expects day count as its argument, and you're passing second count (which is what you get when dividing millisecond count by 1000).
The Answer by NPE is correct.
Solution code example
Here is code to handle the situation correctly.
If your input number is a number of milliseconds since the epoch of start of 1970 in UTC, then create an Instant.
Instant instant = Instant.ofEpochMilli( 1406865600000L );
Determining a date requires a time zone. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still being “yesterday” in Montréal Québec.
So adjust your Instant into a ZonedDateTime object by applying your desired/expected time zone.
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );
Ask for the day-of-week. Java represents each of the seven days of the week in the enum DayOfWeek.
DayOfWeek dow = zdt.getDayOfWeek();
Ask the DayOfWeek object to translate the name of the day of the week to a human language defined in a Locale.
String output = dow.getDisplayName( TextStyle.FULL_STANDALONE , Locale.CANADA_FRENCH );
Dump to console. Results, at least for America/Montreal, are as you expect, Friday 1 AUG.
System.out.println ( "input: " + input + " | instant: " + instant + " | zdt: " + zdt + " | dow: " + dow + " | output: " + output );
input: 1406865600000 | instant: 2014-08-01T04:00:00Z | zdt: 2014-08-01T00:00-04:00[America/Montreal] | dow: FRIDAY | output: vendredi
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