# Always the wrong type

Don´t know what's wrong, I defined two dates:

let d3 = Date()
let d4 = Date.init(timeIntervalSince1970: 1524787201)

and tried this:

convenience init (start startDate: d3, endDate: d4)

-> got this: initializers may only declared within a type
undeclared type d3 / undeclared type d4

Does someone have an idea?

What are you trying to do?

I want to get the time interval between the two dates in years, months, weeks and days - not only in one unit.
my final goal is two get the output in the form:
13 Years 13 months 13 Weeks 13 Days instead of 14 Years 4 Months x Weeks y days
-> But my first step is to add or subtract months to get the different timepoints with which I can calculate...

Date represents a moment in time, a point. So you need a different type to represent a distance between these two points. Something like this looks like a good start:

``````let d1 = Date()
let d2 = Date(timeIntervalSince1970: 1524787201)
let diff = Calendar.current.dateComponents([.year, .month, .day], from: d1, to: d2)
``````

that gives me the components of the date, not the distance...
-> year: 2018 month: 4 day: 7
but I need the distance to today in months, years and days

It seems to work well for me:

``````let now = Date()
let later = now.addingTimeInterval(60 * 60 * 24 * 45) // 45 days later
let diff = Calendar.current.dateComponents([.month, .day], from: now, to: later) // month: 1 day: 14
``````

Very well, thank you!!!!
Do you also know how to put a dateComponent into an integer? Because I cannot divide the dateComponents-output .day by seven to get weeks...
I tried:
let diff = Calendar.current.dateComponents([.day], from: c, to: now)
let i = Int(diff)

and got: Cannot invoke initializer for type 'Int' with an argument list of type '(DateComponents)'

OK, I found it:
let i = Int(diff.day!)

Don´t understand why the ! is important - but it is obviously...

But now I got a problem with Date.init:
while a < i {
var cg = Date.init(TimeIntervalSince1970: 1523095254+a*604800)

and I get: Argument labels '(TimeIntervalSince1970:)' do not match any available overloads
why can't I define cg as a date point?
because few lines earlier that is no problem...

You're using an uppercase "T" in your call. It should be lowercase.

I also tried that but doesn't work...
Now it works with:
...but something strange happens with the calculation

@davidberger There are a lot of best practices you need to follow for proper date calculations. However, I can't find a good document from Apple for it, and their old docs are in Obj-C. @eskimo Is there an updated, Swift version of the old Date and Time Programming Guide? The API docs have pretty much zero coherent guidance.

Basically, you should never use fixed `TimeInterval`s for calculations, as the simple number of seconds doesn't take into account things like leap time, DST changes, or changes in a locale's timezone. Instead, you should use `DateComponents` to add a positive or negative amount of whichever unit you need to an existing date using a `Calendar` instance. If you search StackOverflow there's a ton of info about different date calculations, or you can tell us what you're trying to do.

2 Likes

Is there an updated, Swift version of the [old Date and Time
Programming Guide][ref]?

No, because guides aren’t a thing in the new docs system.

Ultimately I’d expect the relevant content from the old guide to be converted to either introductory material for a specific class or a standalone article. Some of that has happened already — for example, the introductory matearial for the `DateFormatter` class covers the fixed-format date gotcha — but I don’t know if that’s true for all that content.

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

To expand, in my opinion the new docs system (1) looks great and (2) works much worse than the old one. I keep running into older, useful docs that say they are obsolete and I should look to the updated documentation, where I invariably end up on a gutted API reference or just a title page with no particulars about the topic I was researching.

7 Likes

I want to echo this point as well.

Here are just two examples of Apple documentation pages I have accessed and used recently, which have the “This document is no longer being updated” notice:

Xcode Markup Reference

Tree-Based XML Programming Guide

`convenience init (start startDate: d3, endDate: d4)`

1. You're creating an `init()` outside of a type (such as a class or struct)
2. You're passing a variable as a type for `startDate` & `endDate`

Put it inside a type and pass `Date` as the type for `startDate` & `endDate`. For example:

``````final class Foo {
var differenceInDays: Int? = 0

convenience init(startDate date1: Date, endDate date2: Date) {
self.init()

differenceInDays = Calendar.current.dateComponents([.month, .day], from: date1, to: date2).day
}
}

let instance = Foo(startDate: d3, endDate: d4)
``````
``````let startDate = Date(timeIntervalSince1970: 1234567890) // 2009-02-13
let endDate   = Date()                                  // 2019-03-06

let dateComponents = Calendar.current.dateComponents(
[.year, .month, .weekOfMonth, .day],
from: startDate,
to: endDate)

dateComponents.year        // 10
dateComponents.month       //  0
dateComponents.weekOfMonth //  2
dateComponents.day         //  6
``````
``````let formatter = DateComponentsFormatter()
formatter.allowedUnits = [.year, .month, .weekOfMonth, .day]
formatter.unitsStyle = .full
formatter.zeroFormattingBehavior = .dropAll
formatter.string(from: startDate, to: endDate) // "10 years, 2 weeks, 6 days"
formatter.string(from: dateComponents)         // "10 years, 2 weeks, 6 days"
``````

I don't understand your final goal, but `DateComponentsFormatter` can give you a localized string.

thank you so much folks!
I found another solution ´cause I have no idea of classes und types:

for wm in 1...j {
dateComponentw.year = wm
dateComponentw.day = 7*wm

``````let cga = Calendar.current.date(byAdding: dateComponentw, to: cg!)
var tage_a = Calendar.current.dateComponents([.day], from:cga!, to: now)
let test_a = Int(tage_a.day!)

if test_a == wm {
print ("Du bist",wm,"Jahre",wm,"Wochen und",wm,"Tage clean!!!!!!!")
break
}
else if test_a == 0 {
print ("Du bist",wm,"Jahre und",wm,"Wochen clean!!!!")
break
}
else if test_a < 0 {
break
}
``````

}

it just worked, but I added two more loops with for, if and else if to check whether
there are more "triples" such as "3 years 3 weeks 3 days" and so on - and now
it doesn't work...starts running but doesn't stop and no output

@benrimmington: "allowed units" sounds interesting too but i guess that ".weekOfMonth" outputs an int between 1-5 depending on which week in the month the start/end date is and not the amount of weeks?

@suyashsrijan:
I will try this next! thanks!!

OK, now I have at least the error:

Fatal error: Can't form Range with upperBound < lowerBound

I have no idea of what I read somewhere: don't declare arrays as optionals because I don't think I have an array here...
Has anyone another idea?
My first idea was that my "z" in "for i in 1...z" is lower than 1 but it definitely isn´t!

OK shame on me, my z was lower 1