Date Class is lacking

I’m trying to port (well actually rewrite) an application I created in C# a couple of years ago. It’s pretty simply but it has a few basic date manipulations…

Am I alone in believing that the Xojo Date class is pretty seriously lacking? There is no obvious way to do arbitrary formats (even simply things like getting a zero-padded day or month number aren’t easily achievable).

I basically have to recreate from scratch a bunch of simple functions I kind of expect to be able to perform on a date object… Are there plans to improve it? Is there an alternative class around that I haven’t found yet?

I work a lot with dates and never have any problems.
Keep in mind that the dateobject takes its format from the system date format of the computer you are working on
change the system date to the date format of your C# programme
Failing that, write a method to do that for you
then use
dim d as new date
dim bol as boolean
bol = parsedate(oldDateString, d)
Do all calculations with d.TotalSeconds

Gerd

You wrote:

(even simply things like getting a zero-padded day or month number aren’t easily achievable)

Dim DR As New Date
Dim DayStr As String

// Because today is 27, I have to change that to less than 10 (1 number)
DR.Day = 5

// Place the day into a string
DayStr = DR.Day

// Now eventually add a leading 0
If Len(DayStr) = 1 Then
DayStr) = “0” + DayStr
End If
// Same apply to month

Isn’t it easy ?

Can you be more specific about other “lackings”

It’s not really that bad. Subclass and include what you want.

You could also try the FormatDateMBS function in our plugins.
see
http://www.mbsplugins.de/archive/2013-05-26/Introducing_FormatDateMBS_func

No, you are not.

Seems the “Original Post” is referring to something native to Xojo that could be similar to this and this.

Or instead of all that you could do

[code] Dim d As New Date
Dim s As String

s = Format(d.day, “00”)[/code]

[quote=16874:@Emile Schwarz]You wrote:

(even simply things like getting a zero-padded day or month number aren’t easily achievable)

Dim DR As New Date
Dim DayStr As String

// Because today is 27, I have to change that to less than 10 (1 number)
DR.Day = 5

// Place the day into a string
DayStr = DR.Day

// Now eventually add a leading 0
If Len(DayStr) = 1 Then
DayStr) = “0” + DayStr
End If
// Same apply to month

Isn’t it easy ?

Can you be more specific about other “lackings”[/quote]

I maintain an M_Date module that adds a lot of features to Date, including the ability to do arbitrary formats with a ToString function that implements these:

http://msdn.microsoft.com/en-us/library/az4se3k1.aspx
http://msdn.microsoft.com/en-us/library/8kb3ddd4.aspx

I should really put that up on my site, but let me know if you’d like a copy.

Kem, Will your M_Date module take a string and a format and output a date object?

I’ve included a ValidDate function written by Steve Garman that will attempt to validate a date string based on the order of the values regardless of the delimiter used, and return a date if successful. Here is the code for it:


Protected Function ValidDate(text as String, ByRef value As Date, assumePastFuture as integer= 0) As Boolean
  // Written by Steve Garman
  // http://rb.sgarman.net/validDate.php
  
  // If the year provided has only one or 2 digits, check assumePastFuture
  // negative value means the past, positive means future, 0 means current century
  
  // If no year is supplied, assumePastFuture has a granularity of 1 year
  
  Static yearPos as Integer = -9
  Static monthPos as Integer = -9
  Static dayPos as Integer = -9
  
  if yearPos = -9 then // first time through
    yearPos = -1 // only try this once
    // try to work out local date format
    // assume Gregorian calendar
    // assume shortDate contains all 3 numbers
    // don't use NthField or Split in case it contains other characters
    dim d as new date
    // clear any time numbers, in case of unusual shortDate format
    d.TotalSeconds = 0
    // set unique values for year, month & date
    d.SQLDate = "2005-12-31"
    dim s as String = d.ShortDate
    dim pos() As integer
    dim thisPos  as Integer
    
    thisPos = InStr( 0, s, "05" )
    if thisPos > 0  then pos.Append thisPos
    thisPos = InStr( 0, s, "12" )
    if thisPos > 0  then pos.Append thisPos
    thisPos = InStr( 0, s, "31" )
    if thisPos > 0  then pos.Append thisPos
    
    if UBound( pos ) = 2 then
      // we've found all three elements
      // sort them by position in shortDate
      dim typ() As string = Array( "y", "m", "d" )
      pos.SortWith typ
      yearPos = typ.IndexOf( "y" )
      monthPos = typ.IndexOf( "m" )
      dayPos = typ.IndexOf( "d" )
    end if
    
  end if
  if yearPos < 0 or monthPos < 0 or dayPos < 0 then
    // we don't know how to parse the date
    // some might want to set defaults instead of returning false
    Return false
  end if
  
  // now check the date has just numbers and two delimiters
  Dim sep as String
  Dim tmp as String
  Dim i as Integer
  Dim noYearSupplied as Boolean
  
  tmp = text
  
  // first figure out what separator they gave us .. have to both be the same one
  for i = 0 to 9
    tmp = replaceAll(tmp,format(i,"0"),"")
  next
  
  select case len(tmp)
  case 0
    // unable to understand the format entered
    return false
  case 1
    sep = tmp
  case 2
    
    sep = mid(tmp,1,1)
    if sep <> mid(tmp,2,1) then
      // invalid - two different separators
      return false
    end if
    
  else
    return false
  end select
  
  //make array of elements
  Dim dats() as String = Split( text, sep )
  
  if UBound( dats ) <> 2 then
    // add in the missing year ?
    dim tmpDate as new date
    dats.Insert  yearPos, format(tmpDate.year,"0000")
    noYearSupplied = True
  end if
  
  if UBound( dats ) <> 2 then
    //invalid date - should never get here.
    Return false
  end if
  
  dim yr As integer = CDbl( dats( yearPos ) )
  if yr < 100 then
    // fix short year by assuming current century
    // proving that we learned nothing from y2k
    dim today as new Date
    dim century as integer
    century = today.year \\ 100
    century = century * 100
    yr = yr + century
    // use any assumptions about whether the date is past or future to set century
    if assumePastFuture < 0 then
      if yr > today.Year then
        yr = yr - 100
      end if
    elseif assumePastFuture > 0 and yr < today.Year then
      yr = yr + 100
    end if
    dats( yearPos ) = CStr( yr )
  elseif noYearSupplied then
    // use any assumptions about whether the date is past or future to set year
    dim mth as integer = CDbl( dats( monthPos ) )
    dim dy as integer = CDbl( dats( dayPos ) )
    dim today as new Date
    if assumePastFuture < 0 then
      if mth > today.Month or ( mth = today.Month and dy > today.Day )  then
        yr = yr - 1
      end if
    elseif assumePastFuture > 0 and ( mth < today.Month or ( mth = today.Month and dy < today.Day ) ) then
      yr = yr + 1
    end if
    dats( yearPos ) = CStr( yr )
  end if
  
  // put detail into a date object
  dim retVal as new date
  dim yy,mm,dd as Integer
  yy = val( dats( yearPos ) )
  mm = val( dats( monthPos ) )
  dd = val( dats( dayPos ) )
  
  retVal.TotalSeconds = 0
  retVal.Year = yy
  retVal.Month = mm
  retVal.Day = dd
  
  // check the date object is not making corrections
  if retVal.Year <> yy or retVal.Month <> mm or retVal.Day <> dd then
    //probably an invalid day of the month
    Return false
  end if
  
  //populate value ( ByRef side-effect )
  if value = nil Then
    value = new Date
  end if
  value.totalseconds = retVal.TotalSeconds
  return true
End Function

Thanks, I’ll give it another go. I think i’ve tried this function before but I believe if a date string is passed which is dd/mm/yyyy or mm/dd/yyyy it parses and gives preference to mm/dd/yyyy format (i.e. US Style). I may need to modify to allow this to be chosen by the user.

My example perhaps wasn’t the best. I had definitely figured out how to achieve the things I mentioned.

In C# I might do something like

DateTime theDate = DateTime.Now();
DateTime tomorrow = theDate.AddDays(1);
DateTime yesterday = theDAte.AddDays(-1);

Again, fairly simple to achieve a similar thing in Xojo, but much more code. Overall I find, in learning Xojo/Realbasic that classes tend to have fewer helper methods usually.

Thanks Kem, I will look at your date class.

“much more code”?? One or two lines at most.

dim theDate as New Date
dim tomorrow as New Date(theDate)
tomorrow.Day = tomorrow.Day + 1
dim yesterday as New Date(theDate)
yesterday.Day = yesterday.Day - 1

[quote=16874:@Emile Schwarz]You wrote:

(even simply things like getting a zero-padded day or month number aren’t easily achievable)

Isn’t it easy ?

Can you be more specific about other “lackings”[/quote]

It’s not difficult, it just seems a little unnecessary - a basic date formatting feature is pretty handy and available in every other programming language I used (maybe not Turbo Pascal in the 90’s, I can’t remember)

Examples:
.NET (C#/VB et al) - System.DateTime
PHP - Too many Date/Time functions and classes maybe?
Python - Date/Time Types

All of them feature formatting methods, addition/subtraction methods, difference methods and many other handy things.

[quote=17087:@Tim Hare]
dim theDate as New Date
dim tomorrow as New Date(theDate)
tomorrow.Day = tomorrow.Day + 1
dim yesterday as New Date(theDate)
yesterday.Day = yesterday.Day - 1[/quote]

Yikes, I was looking for this. This should be documented in the date class.
I was assuming it would only perform integer addition and cause an overflow (days > 31). But it just works as it should for date arithmetics.

[quote=17087:@Tim Hare]dim theDate as New Date
dim tomorrow as New Date(theDate)
tomorrow.Day = tomorrow.Day + 1
dim yesterday as New Date(theDate)
yesterday.Day = yesterday.Day - 1[/quote]

Granted, I have tested this yet, but how does that work when the modified date becomes invalid? Such as .Day + 1 on the last day of the month?

A safer way would seem to be:

Dim oneDay as Integer = 86400
Dim theDate as New Date
Dim tomorrow as New Date(theDate)
tomorrow.Seconds = tomorrow.Seconds + oneDay

It’s easy for simple things, but appears to be more difficult for more complex manipulations. Again, I’m not saying these things are impossible, I’m just a little surprised as the sparseness of some classes and functions is all.

Haven’t tested that is - one more voice for the “enable post editing” vote :slight_smile:

It is possible to edit ones own post if there is no reply posted yet. However there is a bug in the Forum software, so a browser page refresh will make the edit option available in the top right corner.

[quote=17095:@Dylan Reeve]Granted, I have tested this yet, but how does that work when the modified date becomes invalid? Such as .Day + 1 on the last day of the month?
[/quote]
The month rolls seamlessly, both forward and back. Test it. The year adjusts, too, as necessary.

Does anyone have business days date math already rolled somewhere?