1

Goal/Problem

I want to convert a Date into a String and back to a Date. I am able to do this but I am losing precision on the way. How can I make sure that not a single bit gets lost in the process?

1573827905079978 vs 157382790508

Main code

var now = Date()

var now_as_string = Date.dateAsString(style: .dayMonthYearHourMinuteSecondMillisecondTimezone, date: now)
var back_as_date =   Date.stringAsDate(style: .dayMonthYearHourMinuteSecondMillisecondTimezone, string: now_as_string)

print(Date.dateAsTimeIntervalSince1970WithoutDots(date: now))
print(Date.dateAsTimeIntervalSince1970WithoutDots(date: back_as_date))

Output

1573827905079978

157382790508

Date Extension (the place where the real magic happens)

import Foundation

extension Date {

    enum Style {
        case dayMonthYear
        case dayMonthYearHourMinute
        case dayMonthYearHourMinuteSecondMillisecondTimezone
    }

    static func dateAsString(style: Date.Style, date: Date) -> String{

        let formatter = DateFormatter()
        formatter.dateFormat = fromStyleToString(style: style)

        return formatter.string(from: date)

    }

    private static func fromStyleToString(style: Date.Style) -> String{

        switch style {

        case .dayMonthYear:
            return "dd.MM.yyyy"

        case .dayMonthYearHourMinute:
            return "dd.MM.yyyy HH:mm"

        case .dayMonthYearHourMinuteSecondMillisecondTimezone:
            return "dd.MM.yyyy HH:mm:ss:SSS Z"

        }

    }

    static func stringAsDate(style: Date.Style, string: String) -> Date{

        let formatter = DateFormatter()
        formatter.dateFormat = fromStyleToString(style: style)
        return formatter.date(from: string)!

    }

    static func dateAsTimeIntervalSince1970WithoutDots(date: Date) -> String{
        return String(date.timeIntervalSince1970).replacingOccurrences(of: ".", with: "")
    }

}
timbre timbre
  • 12,648
  • 10
  • 46
  • 77
Goga
  • 349
  • 1
  • 16

1 Answers1

2

A Date is just a number of seconds, as a Double, since the reference date. (This is aliased to "TimeInterval," but it's just a Double.)

If you want it to be a string without losing any information, that's just the string form of the Double:

let nowString = "\(now.timeIntervalSinceReferenceDate)" // "595531191.461246"

And to convert it back, turn the Double into a Date:

let originalDate = Date(timeIntervalSinceReferenceDate: TimeInterval(nowString)!)
originalDate == now // true

You definitely don't want to remove the decimal point. That's an important part of the number.

Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • I am forced to remove any decimal points when I set this value to Firebase. It is the name of a parent. Therefore no decimal points allowed. Thank you for your answer though – Goga Nov 16 '19 at 11:44