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 :frowning:

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!)
:slight_smile:

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:
var cg = c.addingTimeInterval(TimeInterval(a*640800))
...but something strange happens with the calculation :frowning:

@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 TimeIntervals 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

:man_facepalming:

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 :frowning:

@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? :thinking:

@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