I am currently using the following SimpleDateFormat pattern:
String DATE_TIME_FORMAT_PATTERN = "yyyy-MM-dd'T'HH:mm:ss,SSSXXX";
This works fine, however some raspberry Pi java implementations don't recognize it properly:
timestamp 2020-01-21T09:41:45,434Z
In most cases, this won't be an issue, however the offset is buggy for some raspberry PIs; I don't want that. Is there an alternative pattern with the same offset format (+/-HH:mm) that could work? I've tried all kinds of patterns, but none seem to produce the same output.
I also used the following tool to search for such a pattern: https://javadevtools.com/simpledateformat , though it was fruitless.
NOTE: An example output of this format is 1997-07-16T19:20:30,45+01:00 , with a colon in the offset.
If you were using java.time, especially the two classes java.time.OffsetDateTime (pattern symbols are explained in this JavaDoc) and java.time.format.DateTimeFormatter, you or your Raspberry Pi would be able to correctly parse the timestamp (which has a strange format using a comma to separate fractions of second from the seconds).
The following example parses your timestamp and outputs the default format:
public static void main(String[] args) {
String timestamp = "1997-07-16T19:20:30,45+01:00";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss[,SSS]xxx");
OffsetDateTime odt = OffsetDateTime.parse(timestamp, dtf);
System.out.println(odt);
}
Output:
1997-07-16T19:20:30.450+01:00
I confirm that this is not a Pi issue. I switched my local time zone to UTC and ran the following example:
long current = System.currentTimeMillis();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss,SSSXXX");
Date date = new Date(current);
String parsed = format.format(date);
System.out.println(parsed);
2020-08-31T15:05:27,872Z
And the Z appeared, on Windows 10. I have missed that part of the ISO spec. It seems I have to workaround my tests for this situation :). Thanks everyone!
Related
I'am working on reading data from csv file, I'am at the point of reading time data. The data in the csv is written in this way 5/15/2020 10:00:00 AM but when I read I get this : 15/Apr/2020. This is a snippet of what I tried until now.
String dateClosedBug = csvToObjects[1].toString();
String[] splitDateClosedBug = dateClosedBug.split(" ");
DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
Date closedDate = dateFormat.parse(splitDateClosedBug[0]);
System.out.println(closedDate);
csvToObjects[1] is a variable of another treatment. I cannot print the value of closedDate because there is an error in parsing the value. Does anyone have an idea of what should I change in my approach in parsing the value?
java.time
I recommend that you use java.time, the modern Java date and time API, for your date and time work.
DateTimeFormatter csvFormatter = DateTimeFormatter.ofPattern("M/d/u h:mm:ss a", Locale.ENGLISH);
String dateClosedBug = "5/15/2020 10:00:00 AM";
LocalDateTime closedBug = LocalDateTime.parse(dateClosedBug, csvFormatter);
LocalDate closedBugDate = closedBug.toLocalDate();
System.out.println(closedBugDate);
Output from this code snippet is:
2020-05-15
Rather than splitting the string I found it both better and easier to parse it in its entirety. It’s easier to throw information away after parsing than to invent information that you neglected to parse.
Tutorial link: Oracle tutorial: Date Time explaining how to use java.time.
We want to add days to the current date and format it in a specific way. This was solved in Groovy 2.4.13 and the following date manipulation works fine:
today = new Date()+90;today.format('yyyy-MM-dd HH:mm:ss.S');
Result: 2019-12-02 08:07:15.294
In Groovy 2.5.4 the same expression throws this exception:
groovy.lang.MissingMethodException: No signature of method:
java.util.Date.plus() is applicable for argument types: (Integer)
values: [90] Possible solutions: parse(java.lang.String),
split(groovy.lang.Closure), use([Ljava.lang.Object;),
is(java.lang.Object), wait(), clone() at
Script1.run(Script1.groovy:3)
I was able to reproduce this behaviour in "Groovy sandboxes" online:
Working fine here: groovy-playground (Version 2.4.1.5)
Failing here: groovyconsole (Version 2.5.7)
What is the working alternative in this case? I have read about a new Date API, but couldn't find the details about how to use it, with date manipulation (+ 90 days for example).
Take a look at TimeCategory
import groovy.time.TimeCategory
def theDate = use(TimeCategory){new Date() + 90.days}.format('yyyy-MM-dd HH:mm:ss.S')
I agree with Ole V.V.'s recommendations to use the new Date/Time API. Here is how you would write his Java sample in a more Groovy style.
// you can assemble aggregate types by left shifting the aggregates
// I'm not endorsing this approach, necessarily, just pointing it out as an alternative
ZonedDateTime now = LocalDate.now() << LocalTime.now() << ZoneId.of('Africa/Bamako')
// the plus operator is overloaded
ZonedDateTime in90Days = now + 90
// you can pass a String to format without needed a full DateTimeFormatter instance
println in90Days.format('uuuu-MM-dd HH:mm:ss.S')
While Groovy adds some further support for the old Java Date class, I still believe that you should not use it. It was always poorly designed and is now long outdated. Instead use java.time, the modern Java date and time API. I am sorry that I will have to trust you to translate from Java code.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.S");
ZonedDateTime now = ZonedDateTime.now(ZoneId.of("Africa/Bamako"));
ZonedDateTime in90Days = now.plusDays(90);
System.out.println(in90Days.format(formatter));
Output when running just now was:
2020-01-01 08:37:13.3
Please substitute your desired time zone if it didn’t happen to be Africa/Bamako.
Link: Oracle tutorial: Date Time explaining how to use java.time.
You can use Calendar to achieve that
Calendar cal = new GregorianCalendar();
cal.add(Calendar.DATE, 90);
Date date = cal.getTime();
All steps must be separate and not in a single line.
OffsetDateTime odtB = OffsetDateTime.parse("2019-02-02T13:55:00Z");
odtB.toString()
prints 2019-02-02T13:55 as output. As because of this my conversion function is throwing error!!
SimpleDateFormat formatter = new SimpleDateFormat("dd-MMM\''YY HH:mm aa");
String parsedDate = odtB.format(otdB);
How to stop OffsetDateTime or anyOther Java DateTime class from trimming seconds off when seconds are 00??
In java8, you do not need SimpleDateFormat any more, it's troublesome.
I suggest to use ISO_OFFSET_DATE_TIME:
The ISO date-time formatter that formats or parses a date-time with an
offset, such as '2011-12-03T10:15:30+01:00'.
Example:
import java.util.*;
import java.time.*;
import java.time.format.*;
public class HelloWorld{
public static void main(String []args){
OffsetDateTime odtB = OffsetDateTime.parse("2019-02-02T13:55:00Z");
DateTimeFormatter f = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
System.out.print(f.format(odtB)); // 2019-02-02T13:55:00Z
}
}
If you use java.time.LocalDateTime (which you should since Java 8), you can use different DateTimeFormatters, which you can configure (give them a pattern) to not trimming trailing zeros. See the following example using your date String with a slightly adjusted pattern:
LocalDateTime ldt = LocalDateTime.parse("2019-02-02T13:55:00Z", DateTimeFormatter.ISO_DATE_TIME);
System.out.println(ldt.format(DateTimeFormatter.ofPattern("dd-MMM\''YY HH:mm:ss")));
This prints 02-Feb'19 13:55:00, which hopefully is what you want.
SimpleDateFormat is from an old and obsolete way of working with Dates. It is also not Thread-safe and has a lot of other problems. In other words don't use it. You need to use DateTimeFormatter Please read the javadoc (link provided). It gives detailed explanation how to use it. However the cause of your problem is that in your format mask you are missing placeholder for seconds, thus when your String has seconds it doesn't conform with your format. Change the format to dd-MMM-YY HH:mm:ss aa emphases on "ss" - the missing seconds placeholder and it will work
My client/browser is in India and I get the timezoneoffset from javascript
using the following code:
var now = new Date();
var localOffSet = now.getTimezoneOffset(); -330 // for India
int localOffSetMin = (localOffSet)*(-1);
My server is located in New York so I get the offset for it using:
TimeZone timeZone = now.getTimeZone();
int serverOffset = timeZone.getRawOffset();
int serverOffSetMinutes = serverOffset / 60000; // -300 for America/New York
In order to find the local time on my machine, I use this:
int offSets = Math.abs(serverOffSetMinutes-localOffSetMin);
now.setTime(createDt); // createDt is date field value for some column
now.add(Calendar.MINUTE, offSets); // adds offset
Date localDt = now.getTime();
But the date/time I get is 1 hour ahead of the expected time. What am I missing?
Date and Time manipulation with Java SE
You can print a list of supported TimeZones by using the following code.
System.out.println(TimeZone.getAvailableIDs().toString());
You can then find and print the difference between the timezones with the following code. You must be mindful of daylight savings time.
public void printTimeZoneDifference(String from, String to) {
TimeZone easternStandardTime = TimeZone.getTimeZone(from);
TimeZone indiaStandardTime = TimeZone.getTimeZone(to);
long milliseconds = easternStandardTime.getRawOffset() - indiaStandardTime.getRawOffset() + easternStandardTime.getDSTSavings() - indiaStandardTime.getDSTSavings();
String difference = String.format("%02d min, %02d sec", TimeUnit.MILLISECONDS.toMinutes(milliseconds), TimeUnit.MILLISECONDS.toSeconds(milliseconds) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(milliseconds)));
System.out.println("The difference in time between" + easternStandardTime.getDisplayName() + " and " + indiaStandardTime.getDisplayName() + " is " + difference);
}
Although if I were to write something like this I would probably pass a TimeZone object as a parameter and keep the method solely responsible for substraction. Then I would either print the results or make it part of a different method. I didn't structure the post that way because I wanted to include all relevant code in the post.
Date and Time manipulation with Joda
This type of manipulation has already been solved in Java. The Joda Time Library is probably your best bet if you are doing a lot of date manipulation. If you are only manipulating time in this one instance then it would be a bit over kill to include the dependency in your runtime.
Again print out the TimeZones.
public void printDateTimeZones() {
for(String zone : DateTimeZone.getAvailableIDs()) {
System.out.println(zone);
}
}
Then you can return a String of the period (difference) between the two DateTimeZones using the default formatting with the following code.
public String printPeriod(String from, String to) {
Period period = new Period(new DateTime(DateTimeZone.forID(to)), new DateTime(DateTimeZone.forID(from)));
return PeriodFormat.getDefault().print(period);
}
Similarly Joda provides a format builder class which allows you to specify your preferred formatting.
public String printPeriod(String from, String to) {
PeriodFormatter formatter = new PeriodFormatterBuilder()
.printZeroRarelyFirst()
.appendYears().appendSuffix(" Years").appendSeparator(",")
.appendMonths().appendSuffix(" Months").appendSeparator(",")
.appendWeeks().appendSuffix(" Weeks").appendSeparator(",")
.appendDays().appendSuffix(" Days").appendSeparator(",")
.appendHours().appendSuffix(" Hours").appendSeparator(",")
.appendSeconds().appendSuffix(" Seconds").appendSeparator(",")
.appendMillis().appendSuffix(" Milliseconds")
.toFormatter();
return formatter.print(new Period(new DateTime(DateTimeZone.forID(from)), new DateTime(DateTimeZone.forID(to))));
}
A java.util.Date object has no timezone information. It has only a long value, which is the number of milliseconds from 1970-01-01T00:00:00Z (also known as "unix epoch" or just "epoch"). This value is absolutely independent of timezone (you can say "it's in UTC" as well).
To convert this value to another timezone, you don't need to do all these math between the timezones. You just get this millis value and convert it to the desired timezone.
To get the value from javascript, just do:
var d = new Date();
var millis = d.getTime();
The variable millis will contain the number of milliseconds from epoch. In the test I've made, this value is 1499101493296.
To create a java.util.Date object, just do:
Date date = new Date(1499101493296L);
To format this date in the timezone you want, use a SimpleDateFormat:
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Kolkata"));
System.out.println(sdf.format(date));
The output will be:
03/07/2017 22:34:53
If you want a different format, check the javadoc for more information.
Also note that I used a timezone name using IANA format (always in the format Continent/City, like America/Sao_Paulo or Europe/Berlin).
Avoid using the 3-letter abbreviations (like IST or EST) because they are ambiguous and not standard.
To use another timezone, you can use one the IANA's names - check all the available names using TimeZone.getAvailableIDs().
New Java 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 <= 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).
Although you can also use Joda-Time, it is in maintainance mode and is 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).".
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.
Once you have the millis value, the code for creating a date and converting to some timezone is very similar:
ZoneId zone = ZoneId.of("Asia/Kolkata");
ZonedDateTime z = Instant.ofEpochMilli(1499101493296L).atZone(zone);
System.out.println(z); // 2017-07-03T22:34:53.296+05:30[Asia/Kolkata]
The output will be:
2017-07-03T22:34:53.296+05:30[Asia/Kolkata]
If you want a different format, use a DateTimeFormatter:
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss x");
System.out.println(z.format(fmt)); // 03/07/2017 22:34:53 +0530
The output will be:
03/07/2017 22:34:53 +0530
If you want a different format, check the javadoc for more details.
To use another timezone, you can use one the IANA's names - check all the available names using ZoneId.getAvailableZoneIds().
Okay, so here's my issue in Android right now. On our Database there's a timestamp in this format 8/15/2013 2:00:48 PM and through a .NET WebService I get that same time like this in Android: 2013-08-15T14:00:48-07:00. Now I want to convert this format into a Date Time format that I can use for comparison (for example this webservice provides every instance where a device failed at logging in so we want to check the amount of time between occurances to see if there's any issues). Below I have this code where I'm trying to use JODA Time but it's still not returning the correct format:
public static Date convertStringToDate(String input) {
String pattern = "yyyy-MM-dd'T'HH:mm:ssZ";
DateTimeFormatter formatter = DateTimeFormat.forPattern(pattern);
DateTime dateTime = formatter.parseDateTime(input);
return dateTime.toDate();
//printout shows: Thu Aug 15 17:00:48 EDT 2013
}
I know that the server is returning some crappy time format that is hard to work with (it took a while to get this to work in the iOS App we have, and even there it's still rather clunky) so I don't mind changing the webservice or the query if that would make things easier.
I have a very similar format, and I parse it using SimpleDateFormat, try this:
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZZZ", Locale.US);
Date dateTime = format .parse(value);
What i understand is that you have your correct instance of date already and what you need is to parse it to String.
I suggest you use:
DateFormat formatter = new SimpleDateFormat("d/MM/yyyy hh:mm:ss a");
//this will give you the format '8/15/2013 2:00:48 PM'
String d = formatter.format(date);
Hope this helps.
EDIT:
Also seams you want to have your date instance in -07:00 timezone
So you can change your line
DateTime dateTime = formatter.parseDateTime(input);
for
DateTime dateTime = formatter.withZone(DateTimeZone.forID("-07:00")).parseDateTime(input);