I have the following code to validate a date given a date format:
val df = new SimpleDateFormat("MM/dd/yyyy");
df.setLenient(false);
try {
val date = df.parse("11/13/2014");
}
catch {
case pe: ParseException => println("date error")
}
Now, what I need is to obtain the year, month and day in three variables. What is the best way to achieve this? Note that I need a solution based on performance as I need to validate/convert thousands of dates.
java.time
Use Java 8 and the new date/time API. Better, cleaner, future-proof.
val dateFormat = "MM/dd/yyyy"
val dtf = java.time.format.DateTimeFormatter.ofPattern(dateFormat)
val dateString = "11/13/2014"
val d = java.time.LocalDate.parse(dateString, dtf)
val year = d.getYear
2014
val monthNumber = d.getMonthValue
11
You can access a Month enum object.
val month = d.getMonth
Month.NOVEMBER
val dayOfMonth = d.getDayOfMonth
13
Once you have the input parsed into a java.time.LocalDate, you can get the year with getYear, etc.
To validate, catch the DateTimeParseException generated for invalid inputs.
If you want to skip the proper date validation (e.g. for performance) and just extract the Y, M, D - you can split the string and get integers as shown below
val ymd = dateString.split("/").map(_.toInt)
ymd: Array[Int] = Array(11, 13, 2014)
Related
Beginner learner here, trying to add an array of integers (which are meant to be seconds) to an array of Epochs:
Sample input:
AddSeconds = [3,4]
TimeEpoch = [1575165652000, 1576424223000] // Which are 2019-12-01 02:00:52 and 2019-12-15 15:37:03
Desired output:
endDate = [2019-12-01 02:00:55, 2019-12-15 15:37:07]
I need to convert the TimeEpoch to dates with "yyyy-MM-dd hh:mm:ss" format
I need to add "AddSeconds" to the obtained dates
Thanks!
You can do this (I changed your variables to start with a lower-case letter, because Groovy guesses that upper case letter variables are actually classnames, so can cause confusion):
addSeconds = [3,4]
timeEpoch = [1575165652000, 1576424223000]
import java.time.*
import java.time.format.*
def formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss")
def datesAsStrings = [addSeconds, timeEpoch]
.transpose()
.collect { a, t -> Instant.ofEpochMilli(t).plusSeconds(a).atZone(ZoneId.systemDefault()).toLocalDateTime() }
.collect { d -> d.format(formatter) }
datesAsStrings.each { println it }
That takes your two lists, and joins them together with transpose():
[ [3, 1575165652000], [4, 1576424223000] ]
Then for each of these, we create an instant, add the seconds, and convert it to a LocalDateTime using the current system timezone -- You need to consider timezones 😉
Then we convert them to the String format you wanted, and pint each of them out
I am using Joda time to generate a range of dates as follows:
val now = DateTime.now
(0 until 5).map(now.minusDays(_)).foreach(println)
How can I parse the generated dates to yyyy-MM-dd format. I was getting the error "java.lang.IllegalArgumentException: Invalid format" when using DateTimeFormat:
val dtf = DateTimeFormat.forPattern("yyyy-MM-dd")
(0 until 5).map(now.minusDays(_)).foreach(d=>dtf.parseDateTime(d.toString))
Change to:
val now = DateTime.now
(0 until 5).map(now.minusDays(_)).map(d=> d.toString("yyyy-MM-dd"))
What I am encountering is quite peculiar.
My Code:
val aa = "2017-01-17 01:33:00"
val bb = "04:33"
val hour = bb.substring(0, bb.indexOf(":"))
val mins = bb.substring(bb.indexOf(":") + 1, bb.length())
val negatedmins = "-" + mins
val ecoffsethour = hour.toLong
val ecoffsetmins = negatedmins.toLong
println(aa)
val datetimeformatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
val txn_post_date_hkt_date_parsed = LocalDateTime.parse(aa, datetimeformatter)
println(txn_post_date_hkt_date_parsed)
val minushours = txn_post_date_hkt_date_parsed.minusHours(ecoffsethour)
println(minushours)
val minusmins = minushours.minusMinutes(ecoffsetmins)
println(minusmins)
val offsetPostdateDiff = minusmins.toString().replace("T", " ")
println(offsetPostdateDiff)
Output:
2017-01-17 01:33:00
2017-01-17T01:33
2017-01-16T21:33
2017-01-16T22:06
2017-01-16 22:06
In the same code I am changing only the "aa" value to ==> 2017-01-17 01:33:44
Now the output is :
2017-01-17 01:33:44
2017-01-17T01:33:44
2017-01-16T21:33:44
2017-01-16T22:06:44
2017-01-16 22:06:44
Why is the first method not taking seconds field into consideration?
My Requirement is : However the output should come in "yyyy-MM-dd
HH:mm:ss" format.
I'm quite new to Scala. Please enlighten me.
Default format is ISO 8601
The java.time classes use the standard ISO 8601 formats by default when parsing/generating strings to represent date-time value.
The standard format for a local date-time is what you are seeing with the T in the middle: YYYY-MM-DDTHH:MM:SS.SSSSSSSSS.
LocalDateTime ldt = LocalDateTime.now( ZoneId.of( "America/Montreal" ) ) ;
String output = ldt.toString() ;
2017-01-23T12:34:56.789
Your call println( txn_post_date_hkt_date_parsed ) is implicitly calling the built-in toString method on the LocalDateTime object, and thereby asking for the standard ISO 8601 format with the T.
println( txn_post_date_hkt_date_parsed.toString() )
Offsets
On an unrelated note, you are working too hard. The java.time classes handle offsets. I do not understand why you want an offset of such an odd number (four hours and thirty-three minutes), but so be it.
Here is your code revised, but in Java syntax.
String input = "2017-01-17 01:33:00" ;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "yyyy-MM-dd HH:mm:ss" ) ;
LocalDateTime ldt = LocalDateTime.parse( input , f ) ;
OffsetDateTime utc = ldt.atOffset( ZoneOffset.UTC ) ;
ZoneOffset offset = ZoneOffset.of( "-04:33" ) ; // Behind UTC by four hours and thirty-three minutes.
OffsetDateTime odt = utc.withOffsetSameInstant( offset ) ;
You can see this code run live at IdeOne.com. Notice how the wall-clock time of your offset-from-UTC is on the previous date. Same moment in history, same point on the timeline, but viewed through two different wall-clock times (UTC, and four hours and thirty three minutes behind).
The Z on the end is standard ISO 8601 notation, short for Zulu and meaning UTC.
input: 2017-01-17 01:33:00
ldt.toString(): 2017-01-17T01:33
utc.toString(): 2017-01-17T01:33Z
odt.toString(): 2017-01-16T21:00-04:33
It's usually better to explicitly the format in which you want the output.
So, instead of
println datetime
You can do something like this:
println datetimeformat.print(datetime)
Good luck!
Edit: Change made to make the 2 expressions exactly equivalent
Developing an Application where i have to parse the following date:
2015-02-02T11:21:51.895Z
using SimpleDateFormat class. But I am getting a Date Parsing Exception.
Here is my code snippet:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd'T'hh:mm:ss'Z'");`
Date qdate = new GregorianCalendar(0,0,0).getTime();
try {
qdate = sdf.parse(dt);
} catch (ParseException e) {
}
Regarding your input "2015-02-02T11:21:51.895Z" you should see that your assumed pattern does not match the input because the pattern does not expect the millisecond part but the literal "Z".
Beyond this, the pattern you used is wrong because of following reasons:
m = minute
M = month
h = hour of half day (1-12)
H = hour of full day (0-23)
X = timezone designator (because Z is not a literal but stands for UTC+00:00)
So you need (please also refer to javadoc):
yyyy-MM-dd'T'HH:mm:ss.SSSX
There is an error in your format (add .SSS for the miliseconds):
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd'T'hh:mm:ss.SSS'Z'");
Date date = sdf.parse("2015-02-02T11:21:51.895Z");
I'm relatively new to both scala and jodatime, but have been pretty impressed with both. I'm trying to figure out if there is a more elegant way to do some date arithmetic. Here's a method:
private def calcDuration() : String = {
val p = new Period(calcCloseTime.toInstant.getMillis - calcOpenTime.toInstant.getMillis)
val s : String = p.getHours.toString + ":" + p.getMinutes.toString +
":" + p.getSeconds.toString
return s
}
I convert everything to a string because I am putting it into a MongoDB and I'm not sure how to serialize a joda Duration or Period. If someone knows that I would really appreciate the answer.
Anyway, the calcCloseTime and calcOpenTime methods return DateTime objects. Converting them to Instants is the best way I found to get the difference. Is there a better way?
Another side question: When the hours, minutes or seconds are single digit, the resulting string is not zero filled. Is there a straightforward way to make that string look like HH:MM:SS?
Thanks,
John
Period formatting is done by the PeriodFormatter class. You can use a default one, or construct your own using PeriodFormatterBuilder. It may take some more code as you might like to set this builder up properly, but you can use it for example like so:
scala> import org.joda.time._
import org.joda.time._
scala> import org.joda.time.format._
import org.joda.time.format._
scala> val d1 = new DateTime(2010,1,1,10,5,1,0)
d1: org.joda.time.DateTime = 2010-01-01T10:05:01.000+01:00
scala> val d2 = new DateTime(2010,1,1,13,7,2,0)
d2: org.joda.time.DateTime = 2010-01-01T13:07:02.000+01:00
scala> val p = new Period(d1, d2)
p: org.joda.time.Period = PT3H2M1S
scala> val hms = new PeriodFormatterBuilder() minimumPrintedDigits(2) printZeroAlways() appendHours() appendSeparator(":") appendMinutes() appendSuffix(":") appendSeconds() toFormatter
hms: org.joda.time.format.PeriodFormatter = org.joda.time.format.PeriodFormatter#4d2125
scala> hms print p
res0: java.lang.String = 03:02:01
You should perhaps also be aware that day transitions are not taken into account:
scala> val p2 = new Period(new LocalDate(2010,1,1), new LocalDate(2010,1,2))
p2: org.joda.time.Period = P1D
scala> hms print p2
res1: java.lang.String = 00:00:00
so if you need to hanldes those as well, you would also need to add the required fields (days, weeks, years maybe) to the formatter.
You might want to take a look at Jorge Ortiz's wrapper for Joda-Time, scala-time for something that's a bit nicer to work with in Scala.
You should then be able to use something like
(calcOpenTime to calcCloseTime).millis
Does this link help?
How do I calculate the difference between two dates?
This question has more than one answer! If you just want the number of whole days between two dates, then you can use the new Days class in version 1.4 of Joda-Time.
Days d = Days.daysBetween(startDate, endDate);
int days = d.getDays();
This method, and other static methods on the Days class have been designed to operate well with the JDK5 static import facility.
If however you want to calculate the number of days, weeks, months and years between the two dates, then you need a Period By default, this will split the difference between the two datetimes into parts, such as "1 month, 2 weeks, 4 days and 7 hours".
Period p = new Period(startDate, endDate);
You can control which fields get extracted using a PeriodType.
Period p = new Period(startDate, endDate, PeriodType.yearMonthDay());
This example will return not return any weeks or time fields, thus the previous example becomes "1 month and 18 days".