I have the following Swift (Swift 3) function to make a date (Date) with date components (DateComponents).
func makeDate(year: Int, month: Int, day: Int, hr: Int, min: Int, sec: Int) -> NSDate {
let calendar = NSCalendar(calendarIdentifier: .gregorian)!
let components = NSDateComponents()
components.year = year
components.month = month
components.day = day
components.hour = hr
components.minute = min
components.second = sec
let date = calendar.date(from: components as DateComponents)
return date! as NSDate
}
If I use it, it will return a GMT date.
override func viewDidLoad() {
super.viewDidLoad()
let d = makeDate(year: 2017, month: 1, day: 8, hr: 22, min: 16, sec: 50)
print(d) // 2017-01-08 13:16:50 +0000
}
What I actually want to return is a date (2017-01-08 22:16:50) literally based on those numbers. How can I do that with DateComponents? Thanks.
The function does return the proper date. It's the print function which displays the date in UTC.
By the way, the native Swift 3 version of your function is
func makeDate(year: Int, month: Int, day: Int, hr: Int, min: Int, sec: Int) -> Date {
var calendar = Calendar(identifier: .gregorian)
// calendar.timeZone = TimeZone(secondsFromGMT: 0)!
let components = DateComponents(year: year, month: month, day: day, hour: hr, minute: min, second: sec)
return calendar.date(from: components)!
}
But if you really want to have UTC date, uncomment the line to set the time zone.
NSDate doesn't know anything about time zones. It represents a point in time independent of any calendars or time zones. Only when printing it out like you did here it is converted to GMT. That's OK though - this is only meant for debugging. For real output use a NSDateFormatter to convert the date to a string.
As a hacky solution you might of course just configure your calendar to use GMT when creating your date object from your components. That way you will get the string you expect. Of course any other calculation with that date then might end up wrong.
Related
I wrote the following code :
val reg = "([\\d]{4})-([\\d]{2})-([\\d]{2})(T)([\\d]{2}):([\\d]{2})".r
val dataExtraction: String => Map[String, String] = {
string: String => {
string match {
case reg(year, month, day, symbol, hour, minutes) =>
Map(YEAR -> year, MONTH -> month, DAY -> day, HOUR -> hour)
case _ => Map(YEAR -> "", MONTH -> "", DAY -> "", HOUR -> "")
}
}
}
val YEAR = "YEAR"
val MONTH = "MONTH"
val DAY = "DAY"
val HOUR = "HOUR"
This function is supposed to be applied to strings having the following format: 2018-08-22T19:10:53.094Z
When I call the function :
dataExtractions("2018-08-22T19:10:53.094Z")
Your pattern, for all its deficiencies, does work. You just have to unanchor it.
val reg = "([\\d]{4})-([\\d]{2})-([\\d]{2})(T)([\\d]{2}):([\\d]{2})".r.unanchored
. . .
dataExtraction("2018-08-22T19:10:53.094Z")
//res0: Map[String,String] = Map(YEAR -> 2018, MONTH -> 08, DAY -> 22, HOUR -> 19)
But the comment from #CAustin is correct, you could just let the Java LocalDateTime API handle all the heavy lifting.
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter._
val dt = LocalDateTime.parse("2018-08-22T19:10:53.094Z", ISO_DATE_TIME)
Now you have access to all the data without actually saving it to a Map.
dt.getYear //res0: Int = 2018
dt.getMonthValue //res1: Int = 8
dt.getDayOfMonth //res2: Int = 22
dt.getHour //res3: Int = 19
dt.getMinute //res4: Int = 10
dt.getSecond //res5: Int = 53
Your pattern matches only strings that look exactly like yyyy-mm-ddThh:mm, while the one you are testing against has milliseconds and a Z at the end.
You can append .* at the end of your pattern to cover strings that have additional characters at the end.
In addition, let me show you a more idiomatic way of writing your code:
// Create a type for the data instead of using a map.
case class Timestamp(year: Int, month: Int, day: Int, hour: Int, minutes: Int)
// Use triple quotes to avoid extra escaping.
// Don't capture parts that you will not use.
// Add .* at the end to account for milliseconds and timezone.
val reg = """(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}).*""".r
// Instead of empty strings, use Option to represent a value that can be missing.
// Convert to Int after parsing.
def dataExtraction(str: String): Option[Timestamp] = str match {
case reg(y, m, d, h, min) => Some(Timestamp(y.toInt, m.toInt, d.toInt, h.toInt, min.toInt))
case _ => None
}
// It works!
dataExtraction("2018-08-22T19:10:53.094Z") // => Some(Timestamp(2018,8,22,19,10))
I have 2 variables where I get 2 times from datePicker and I need to save on a variable the difference between them.
let timeFormatter = DateFormatter()
timeFormatter.dateFormat = "HHmm"
time2 = timeFormatter.date(from: timeFormatter.string(from: datePicker.date))!
I have tried to get the timeIntervalSince1970 from both of them and them substract them and get the difference on milliseconds which I will turn back to hours and minutes, but I get a very big number which doesn't corresponds to the actual time.
let dateTest = time2.timeIntervalSince1970 - time1.timeIntervalSince1970
Then I have tried using time2.timeIntervalSince(date: time1), but again the result milliseconds are much much more than the actual time.
How I can get the correct time difference between 2 times and have the result as hours and minutes in format "0823" for 8 hours and 23 minutes?
The recommended way to do any date math is Calendar and DateComponents
let difference = Calendar.current.dateComponents([.hour, .minute], from: time1, to: time2)
let formattedString = String(format: "%02ld%02ld", difference.hour!, difference.minute!)
print(formattedString)
The format %02ld adds the padding zero.
If you need a standard format with a colon between hours and minutes DateComponentsFormatter() could be a more convenient way
let formatter = DateComponentsFormatter()
formatter.allowedUnits = [.hour, .minute]
print(formatter.string(from: time1, to: time2)!)
TimeInterval measures seconds, not milliseconds:
let date1 = Date()
let date2 = Date(timeIntervalSinceNow: 12600) // 3:30
let diff = Int(date2.timeIntervalSince1970 - date1.timeIntervalSince1970)
let hours = diff / 3600
let minutes = (diff - hours * 3600) / 60
To get duration in seconds between two time intervals, this can be used -
let time1 = Date(timeIntervalSince1970: startTime)
let time2 = Date(timeIntervalSince1970: endTime)
let difference = Calendar.current.dateComponents([.second], from: time1, to: time2)
let duration = difference.second
Now you can do it in swift 5 this way,
func getDateDiff(start: Date, end: Date) -> Int {
let calendar = Calendar.current
let dateComponents = calendar.dateComponents([Calendar.Component.second], from: start, to: end)
let seconds = dateComponents.second
return Int(seconds!)
}
The date format that I'm passing my DateFormatter is not working.
Why is the year appearing as the first component of the date when I specify month in the dateFormat? Why is my am/pm marker in the dateFormat being ignored? Finally, why or how do I correct for time zone? I didn't specify, yet a different time zone has been used.
Thanks!
if let publishDateString = post["publishDate"] as? String {
print("publishDateString is \(publishDateString)") // 2/17/2016 2:49:00 PM
let myDateFormatter = DateFormatter()
myDateFormatter.dateFormat = "M/d/yyyy h:mm:ss a"
let dateFromString = myDateFormatter.date(from: publishDateString)!
print("My date from string is \(dateFromString)") // 2016-02-17 19:49:00 +0000
}
I would want to initialize a gregorian date like this
boost::gregorian::date d = { 1, 1, 1 };
but year = 1 is not allowed.
How can I create a day before Jesus was born ?
The current implementation of Gregorian date supports dates in the range 1400-Jan-01 to 9999-Dec-31. So handling a date outside this range is no directly possible.
I have a row like this,
[[[Date {Wed Dec 18 2013 00:00:00 GMT+0530 (India Standard Time)}, 0, null, 19 more...],
[Date {Tue Dec 17 2013 00:00:00 GMT+0530 (India Standard Time)}, 0, null, 19 more...],
[Date {Mon Dec 16 2013 00:00:00 GMT+0530 (India Standard Time)}, 0, null, 19 more...],
...4 more...]]
Earlier the date in the above line was like this,
['2013-11-18', 0, null, null, 0, null, null, 0, null, null, 0, null, null, 0, null, null, 0, null, null, 0, null, null]
and so on... So, I just converted into above format. But, how to pass it into google charts? Since now,I have used:
googledata.addRows(chartdata)
Where the chartdata contains above lines and I have also tried:
var googledata = google.visualization.arrayToDataTable(chartdata);
I have rows like this,
googledata.addColumn('date', 'Date');
forloop
{
googledata.addColumn('number', items[i]);
googledata.addColumn({type:'string', role:'annotation'});
googledata.addColumn({type:'string', role:'annotationText'});
}
Total 7 items are there and am generating that using for loop.
help me
The arrayToDataTable method does not support inputting dates, so you can't use that. Your dates need to be input in one of two ways, depending on how you are loading the data. If you are manually building the DataTable, like this:
var googledata = new google.visualization.DataTable();
googledata.addColumn('date', 'Date');
// add other columns
then you need to input your dates as Date objects. As an example, this date Date {Wed Dec 18 2013 00:00:00 GMT+0530 (India Standard Time)} would be input as new Date(2013, 11, 18) (months are zero-indexed, so December is 11 not 12). If you are constructing your DataTable from a JSON string, like this:
var googledata = new google.visualization.DataTable(jsonData);
then you need to use a custom string format for the dates. It looks similar to a standard Date object, but is a string and does not contain the new keyword; your example date would be input as "Date(2013, 11, 18)".
[Edit - how to use a DataView to convert date strings into Date objects]
You can also use a DataView to convert date strings into Date objects. You need to parse the date string into its component parts and use those to construct a Date object. Assuming a date string in the format 'yyyy-MM-dd' in column 0 of your DataTable, this is how you would convert it to a Date object:
var view = new google.visualization.DataView(googledata);
view.setColumns([{
type: 'date',
label: data.getColumnLabel(0),
calc: function (dt, row) {
var dateArray = dt.getValue(row, 0).split('-');
var year = dateArray[0];
var month = dateArray[1] - 1; // subtract 1 to convert to javascript's 0-indexed months
var day = dateArray[2]; //The day is the third split
return new Date(year, month, day);
}
}, /* list of the rest of your column indices */]);