Convert time (without date) to UTC time in Scala - scala

I have a string of time I need to parse that's currently in a 12 hour clock format. Some examples are the following:
11:30 PM
07:00 AM
These times are currently in eastern time zone. What's the best way to convert those strings to a string that contains the UTC equivalent?

How about:
import java.text.SimpleDateFormat
val fmtFromLocal = new SimpleDateFormat("hh:mm a z") // z parses time zone
val fmtToGmt = new SimpleDateFormat("hh:mm a")
def toGmt(t: String): String = fmtToGmt.format(fmtFromLocal.parse(s + " EST"))
Unfortunately, this fails when the local timezone is not GMT, as .parse() returns a local time.
Corrected:
import java.text.SimpleDateFormat
import java.util.{Date, TimeZone}
val localTz = TimeZone.getDefault()
val currentOffset = localTz.getOffset(System.currentTimeMillis)
val fmtFromLocal = new SimpleDateFormat("hh:mm a z") // z parses time zone
val fmtToGmt = new SimpleDateFormat("hh:mm a")
def toGmt(t: String): String = {
val time = fmtFromLocal.parse(t).getTime()
val timeUtc = time + currentOffset
fmtToGmt.format(new Date(timeUtc))
}
(Not tested)

Use Joda-Time.
val tz = DateTimeZone.forTimeZone(TimeZone.getTimeZone("EST"))
// You can also use DateTimeZone.forID(), but it requires an id in form
// like 'Europe/Paris', but I don't remember which such ID corresponds to Eastern time
val fmt = DateTimeFormat.forPattern("hh:mm a")
val fmtIn = fmt.withZone(tz)
val fmtOut = fmt.withZone(DateTimeZone.UTC)
val strIn = "11:30 PM"
val strOut = fmtOut.print(fmtIn.parseDateTime(strIn))
Easy and pretty straightforward. I'm getting 04:40 AM for 11:30 PM, which seems to be correct, and I'm in UTC+4 zone, so it this method works independently on local time zone.

Related

How to write functions for CurrentYear and PreviousYear in scala?

I have this scenario where I am fetching for CurrentDate. Adding to that I also want to fetch data from CurrentYear and PreviousYear
def getCurrentDate: String = {
val cal = Calendar.getInstance()
cal.add(Calendar.DATE, amount = 0)
new SimpleDateFormat(pattern = "yyyyMMdd").format(cal.getTime())
}
def getCurrentYear: String = {
val cal = Calendar.getInstance()
cal.add(Calendar.DATE, amount = 0)
new SimpleDateFormat(pattern = "yyyyMMdd").format(cal.getTime())
}
I am actually figuring out on how to write this simple function
First of all, you need to know that the current year depends on your timezone.
So you first need to choose the timezone for which you want to know the year... specially in edge scenarios like new years eve.
That being said, you can do this:
import java.time._
val yourTZ: ZoneId = ...
def currentDate = Instant.now.atZone(yourTZ).toString.take(10) // because the toString uses ISO formatting
def currentYear = currentDate.take(4)
def previousYear = (currentYear.toInt-1).toString

Subtract days from a date in the form of a string

I have a date in the form of a string like below
"08/08/2017 11:43"
I was trying to subtract a day from the above date string so the final output would be "07/08/2017 11:43"
I tried it with the below code
val x = "18/8/2017 11:43"
val formatter = DateTimeFormat.forPattern("dd/MM/yyyy HH:mm");
val dt = formatter.parseDateTime(x);
println(dt.minusDays(1))
But, the output that I got is 2017-08-17T11:43:00.000-07:00
Is there a better way of doing this?
You need the formatter for both parsing and formatting for output.
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
val x = "18/8/2017 11:43"
val formatter = DateTimeFormatter.ofPattern("d/M/yyyy HH:mm")
val dt = LocalDateTime.parse(x, formatter)
val res = dt.minusDays(1).format(formatter) //res: String = 17/8/2017 11:43

Date/Time formatting Scala

I'm trying to assert date and time displayed on the page
Problem is it's returning value of "2017-03-11T09:00" instead of "2017-03-11 09:00:00" and I'm confused why as the pattern = yyyy-MM-dd HH:mm:ss
Any ideas?
def getDate :String = {
val timeStamp = find(xpath("//*[#id=\"content\"]/article/div/div/table/tbody/tr[5]/td/div/p[4]")).get.underlying.getText
val stripDate: Array[String] = timeStamp.split("Timestamp:\n")
stripDate(1)
}
def datePattern(date: String): LocalDateTime = {
val pattern: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
val result = LocalDateTime.parse(date, pattern)
result
}
def checkDatePattern() = datePattern(getDate).toString shouldBe getDate
The DateTimeFormatter only gets used for the parse operation. It doesn't influence the result of toString. If you want to convert your LocalDateTime to a String in a certain format you have to call
date.format(pattern)
I've managed to get the result I wanted by just deleting some parts of the code. As long as the date is in displayed in the correct format, the test passes if it's displayed in an incorrect format it fails, which is good enough for me. Thanks for your input. CASE CLOSED
def getDate :String = {
val timeStamp = find(xpath("//*[#id=\"content\"]/article/div/div/table/tbody/tr[5]/td/div/p[4]")).get.underlying.getText
val stripDate: Array[String] = timeStamp.split("Timestamp:\n")
stripDate(1)
}
def datePattern(date: String): LocalDateTime = {
val pattern: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
LocalDateTime.parse(date, pattern)
}
def checkDatePattern() = datePattern(getDate)

How to find out adjusted hour in scala

I have some examples:
case1. val date1 = new DateTime("2015-08-03T04:59:00.000")
output: new DateTime("2015-08-03T04:00:00.000")
case2. val date2 = new DateTime("2015-08-03T04:15:00.000")
output: new DateTime("2015-08-03T04:00:00.000")
means for any datetime if the time is more the 1 minute output should be start of hour. Example for day: datetime.withTimeAtStartOfDay.
I'm assuming that you are using the joda time DateTime. If you are, then you can use the following method
def dateTimeAtStartOfHour(s: String) = {
new DateTime(s)
.withMinuteOfHour(0)
.withSecondOfMinute(0)
.withMillisOfSecond(0)
}
val date1 = dateTimeAtStartOfHour("2015-08-03T04:59:00.000")
val date2 = dateTimeAtStartOfHour("2015-08-03T04:15:00.000")
val date3 = dateTimeAtStartOfHour("2015-08-03T04:59:13.000")
Output is
date1: org.joda.time.DateTime = 2015-08-03T04:00:00.000-04:00
date2: org.joda.time.DateTime = 2015-08-03T04:00:00.000-04:00
date3: org.joda.time.DateTime = 2015-08-03T04:00:00.000-04:00
You need to use "truncate" analogue, which is called roundFloorCopy in joda:
https://stackoverflow.com/a/8510936/1349366

Iterate over dates range (the scala way)

Given a start and an end date I would like to iterate on it by day using a foreach, map or similar function. Something like
(DateTime.now to DateTime.now + 5.day by 1.day).foreach(println)
I am using https://github.com/nscala-time/nscala-time, but I get returned a joda Interval object if I use the syntax above, which I suspect is also not a range of dates, but a sort of range of milliseconds.
EDIT: The question is obsolete. As advised on the joda homepage, if you are using java 8 you should start with or migrate to java.time.
You may use plusDays:
val now = DateTime.now
(0 until 5).map(now.plusDays(_)).foreach(println)
Given start and end dates:
import org.joda.time.Days
val start = DateTime.now.minusDays(5)
val end = DateTime.now.plusDays(5)
val daysCount = Days.daysBetween(start, end).getDays()
(0 until daysCount).map(start.plusDays(_)).foreach(println)
For just iterating by day, I do:
Iterator.iterate(start) { _ + 1.day }.takeWhile(_.isBefore(end))
This has proven to be useful enough that I have a small helper object to provide an implicit and allow for a type transformation:
object IntervalIterators {
implicit class ImplicitIterator(val interval: Interval) extends AnyVal {
def iterateBy(step: Period): Iterator[DateTime] = Iterator.iterate(interval.start) { _ + step }
.takeWhile(_.isBefore(interval.end))
def iterateBy[A](step: Period, transform: DateTime => A): Iterator[A] = iterateBy(step).map(transform)
def iterateByDay: Iterator[LocalDate] = iterateBy(1.day, { _.toLocalDate })
def iterateByHour: Iterator[DateTime] = iterateBy(1.hour)
}
}
Sample usage:
import IntervalIterators._
(DateTime.now to 5.day.from(DateTime.now)).iterateByDay // Iterator[LocalDate]
(30.minutes.ago to 1.hour.from(DateTime.now)).iterateBy(1.second) // Iterator[DateTime], broken down by second
Solution with java.time API using Scala
Necessary import and initialization
import java.time.temporal.ChronoUnit
import java.time.temporal.ChronoField.EPOCH_DAY
import java.time.{LocalDate, Period}
val now = LocalDate.now
val daysTill = 5
Create List of LocalDate for sample duration
(0 to daysTill)
.map(days => now.plusDays(days))
.foreach(println)
Iterate over specific dates between start and end using toEpochDay or getLong(ChronoField.EPOCH_DAY)
//Extract the duration
val endDay = now.plusDays(daysTill)
val startDay = now
val duration = endDay.getLong(EPOCH_DAY) - startDay.getLong(EPOCH_DAY)
/* This code does not give desired results as trudolf pointed
val duration = Period
.between(now, now.plusDays(daysTill))
.get(ChronoUnit.DAYS)
*/
//Create list for the duration
(0 to duration)
.map(days => now.plusDays(days))
.foreach(println)
This answer fixes the issue of mrsrinivas answer, that .get(ChronoUnits.DAYS) returns only the days part of the duration, and not the total number of days.
Necessary import and initialization
import java.time.temporal.ChronoUnit
import java.time.{LocalDate, Period}
Note how above answer would lead to wrong result (total number of days is 117)
scala> Period.between(start, end)
res6: java.time.Period = P3M26D
scala> Period.between(start, end).get(ChronoUnit.DAYS)
res7: Long = 26
Iterate over specific dates between start and end
val start = LocalDate.of(2018, 1, 5)
val end = LocalDate.of(2018, 5, 1)
// Create List of `LocalDate` for the period between start and end date
val dates: IndexedSeq[LocalDate] = (0L to (end.toEpochDay - start.toEpochDay))
.map(days => start.plusDays(days))
dates.foreach(println)
you can use something like that:
object Test extends App {
private val startDate: DateTime = DateTime.now()
private val endDate: DateTime = DateTime.now().plusDays(5)
private val interval: Interval = new Interval(startDate, endDate)
Stream.from(0,1)
.takeWhile(index => interval.contains(startDate.plusDays(index)))
.foreach(index => println(startDate.plusDays(index)))
}
In this case, the Scala way is the Java way:
When running Scala on Java 9+, we can use java.time.LocalDate::datesUntil:
import java.time.LocalDate
import collection.JavaConverters._
// val start = LocalDate.of(2019, 1, 29)
// val end = LocalDate.of(2018, 2, 2)
start.datesUntil(end).iterator.asScala
// Iterator[java.time.LocalDate] = <iterator> (2019-01-29, 2019-01-30, 2019-01-31, 2019-02-01)
And if the last date is to be included:
start.datesUntil(end.plusDays(1)).iterator.asScala
// 2019-01-29, 2019-01-30, 2019-01-31, 2019-02-01, 2019-02-02
import java.util.{Calendar, Date}
import scala.annotation.tailrec
/** Gets date list between two dates
*
* #param startDate Start date
* #param endDate End date
* #return List of dates from startDate to endDate
*/
def getDateRange(startDate: Date, endDate: Date): List[Date] = {
#tailrec
def addDate(acc: List[Date], startDate: Date, endDate: Date): List[Date] = {
if (startDate.after(endDate)) acc
else addDate(endDate :: acc, startDate, addDays(endDate, -1))
}
addDate(List(), startDate, endDate)
}
/** Adds a date offset to the given date
*
* #param date ==> Date
* #param amount ==> Offset (can be negative)
* #return ==> New date
*/
def addDays(date: Date, amount: Int): Date = {
val cal = Calendar.getInstance()
cal.setTime(date)
cal.add(Calendar.DATE, amount)
cal.getTime
}