TIP: How to screw up a promising Date

No, not that kind of date.

Sometimes you want to set a Date to a certain day. But it’s easy to do this wrong as I found out.

Wrong:

theDate.Day = Day theDate.Month = Month

Right

theDate.Month = Month
theDate.Day = Day

Why? If the existing theDate is set February and you assign a day of 30 to it, it becomes invalid (Feb 30) and resets itself to 1. For example, assign the date of Jan 30 to it will result in it being set to Jan 1. This is particularly tricky to debug if you are making a new date on the fly as the bug will only show up when the program is run in February and not in March.

My public service announcement for the day. Maybe someone knows an even better way to avoid this.

Use the Classic framework.

Don’t use the Classic framework Date. Use the Constructor of Xojo.Core.Date to create your Dates and then use Xojo.Core.DateInterval. The new framework dates are much more reliable and safe. Note that they are immutable after creation, so you would do something like this:

dim date1 as new Xojo.Core.Date(2018, 2, 28, Xojo.Core.TimeZone.current) // date1 is immutable dim change as new Xojo.Core.DateInterval(0, 0, 1) // 0 years, 0 months, 1 day dim date2 as Xojo.Core.Date = date1 + change

Edit (Paul): Updated links

[quote=413105:@Gavin Smith]dim date1 as new Xojo.Core.Date(2018, 2, 28, Xojo.Core.TimeZone.current) // date1 is immutable
dim change as new Xojo.Core.DateInterval(0, 0, 1) // 0 years, 0 months, 1 day
dim date2 as Xojo.Core.Date = date1 + change[/quote]

Compare the new code to the old one

[quote=413092:@Stephen Dodd]theDate.Month = Month
theDate.Day = Day[/quote]

I am pretty sure there are more lazy people like me who do not use the new framework just because we need to write a page of code where we previously just wrote 2-3 lines… :wink:

Hi Stephen, good tip, just to clear this up, if theDate is set February and you assign a day of 30, if that February has only 28 days, then theDate will have a date of March 02, if February has 29 days, theDate will be March 01. If you have theDate set in February and do:

theDate.Day = 90

the date value in theDate will be May 1st (28 + 31 + 30 + 1) or April 30 (29 + 31 + 30)

Isn’t this:

dim date1 as new Xojo.Core.Date(2018, 2, 28, Xojo.Core.TimeZone.current) // date1 is immutable dim change as new Xojo.Core.DateInterval(0, 0, 1) // 0 years, 0 months, 1 day dim date2 as Xojo.Core.Date = date1 + change
the same as this:

dim theDate as new date(2018, 2, 28) theDate.day = theDate.day + 1
but without the need to use a second theDate?

Sorry I don’t use Xojo.Core.Date so I don’t understand why one code is better than the other.

Maybe Xojo API 2.0 will make the Classic Date better.

Is the new framework going away or being refactored in a way that I’ll have to rewrite later?

Oh, I didn’t even know that date constructor existed. Learn something new every day!

You’re right.

I sometimes set the day to 0 if I want it to become the last day of the previous month.

From what I understand about Xojo API 2.0, the new framework stay for a long time without changes.

Sure sure, it’s a few extra characters. You can stick a using Xojo.Core at the top of your code to avoid the namespacing and it’s not required on iOS at all. I’m lazy too so I like my dates to be reliable without lots of head scratching and debugging :wink: FWIW, I’d expect most of the functionality of the “new” Date to be rolled into the classic Date for API 2.0.

The problem is that multiple lines of code like in the original post:

'
theDate.Day = Day
theDate.Month = Month
'

may be right next to each other or separated by many lines or across methods. And, to make dates “do the right thing” they need to be done in a specific order. No manner of rolling the new date functions into the classic date API style can fix this as long as the members (day, month year etc) are mutable since that lets you do them in any order anywhere.

I’m finding I’m writing less code with the new framework for example finding a due date for an invoice where payment terms are 20th following month

Dim DueDate As Date = Date.Now + New DateInterval(0, 1, 20 - Date.Now.Day)