Format dates w/ PHP syntax (WIP)

Share your advanced PureBasic knowledge/code with the community.
User avatar
kenmo
Addict
Addict
Posts: 1967
Joined: Tue Dec 23, 2003 3:54 am

Format dates w/ PHP syntax (WIP)

Post by kenmo »

Here's a useful chunk of code... I have "mostly" mimicked the functionality of PHP's date() formatting function in PureBasic.
Think of it as an expanded version of PB's own FormatDate() command.


For PHP's syntax, see their documentation here: http://php.net/manual/en/function.date.php

EnableExplicit-friendly, cross-platform compileable, comes with a ready-to-run example!
A single procedure, with no global variables or macros to carry with it!

But be aware it is a work in progress!
A few of the format codes have not been implemented yet, and the time zone codes are not implemented on Mac/Linux!
And it is not 100% verified... (for example, some padding lengths might differ from PHP's?)

I am completely open to suggestions, contributions, and improvements!

Code: Select all

; +---------------+
; | PHPFormatDate |
; +---------------+
; |  8.21.2011 . Creation (PB 4.51)
; |   .22.     . Added full date/time combos, Swatch time, difference from GMT
; |   .23.     - Version 1.0 (for PB forums)
; |  5.11.2016 - Version 1.1 (corrected day prefixes such as "st")
; |  1.23.2017 - Version 1.2 (corrected GMT offset bug when passing midnight)
;
;
;
; This procedure mimics the native date() function of the PHP language.
; It can be used as an expanded replacement for PB's FormatDate() function,
; but be aware that it uses completely different syntax!
; The Timestamp argument defaults to -1, which is replaced by the current time.
;
; The format syntax (list of character codes) matches PHP's syntax here:
; ***  http://php.net/manual/en/function.date.php  ***
;
;
;
; Note the following exceptions, and their contribution to the result:
;
; 'u' (microseconds) PB timestamps do not use microseconds,  always becomes "000000"
; 'W' (ISO week number) not implemented,                            becomes "?"
; 'o' (ISO year) not implemented,                                   becomes "?"
; 'e' (time zone ID) not implemented,                               becomes "?"
; 'I' (daylight savings flag) not implemented,                      becomes "?"
; 'T' (time zone abbreviation) not implemented,                     becomes "?"
;
; Also:
;  *   Time zones are not yet implemented on Mac/Linux. GMT offset will alway be 00:00.
;







; PHPFormatDate (Version 1.2)
Procedure.s PHPFormatDate(Format.s, Timestamp.i = -1)
  Protected Result.s
  Protected Year.i, Month.i, Day.i, Hour.i, Minute.i, Second.i
  Protected FromGMT.i, GMTHour.s, GMTMinute.s, Temp.i
  Protected *C.CHARACTER
 
 
  ; Use current time, by default
  If (Timestamp = -1)
    Timestamp = Date()
  EndIf
 
 
  ; OS-dependent code for getting time zone info (GMT offset)
  CompilerIf (#PB_Compiler_OS = #PB_OS_Windows)
    Protected GMTTime.SYSTEMTIME, LocalTime.SYSTEMTIME
   
    ; Retrieve GMT and local times
    GetSystemTime_(GMTTime)
    GetLocalTime_(LocalTime)
    FromGMT = (LocalTime\wHour - GMTTime\wHour)*60 + (LocalTime\wMinute - GMTTime\wMinute)
    If (GMTTime\wDayOfWeek = (LocalTime\wDayOfWeek + 1) % 7)
      FromGMT - 24*60
    ElseIf (GMTTime\wDayOfWeek = (LocalTime\wDayOfWeek + 7 - 1) % 7)
      FromGMT + 24*60
    EndIf
   
    ; Format time zone offset appropriately
    If (FromGMT > 0)
      GMTHour   = "+" + RSet(Str(FromGMT / 60), 2, "0")
      GMTMinute = RSet(Str(FromGMT % 60), 2, "0")
    Else
      GMTHour   = "-" + RSet(Str((0-FromGMT) / 60), 2, "0")
      GMTMinute = RSet(Str((0-FromGMT) % 60), 2, "0")
    EndIf
   
  CompilerElse
 
    ; Mac and Linux GMT code not yet implemented
    FromGMT   =   0
    GMTHour   = "+00"
    GMTMinute =  "00"
   
  CompilerEndIf
 
 
  ; Extract numeric timestamp values
  Year   = Year  (Timestamp)
  Month  = Month (Timestamp)
  Day    = Day   (Timestamp)
  Hour   = Hour  (Timestamp)
  Minute = Minute(Timestamp)
  Second = Second(Timestamp)
 
 
  ; Parse through each format character
  Result = ""
  *C     = @Format
  While (*C\c)
    Select (*C\c)
   
      ; Day representations
      Case 'd' : Result + RSet(Str(Day), 2, "0")
      Case 'D'
        Select (DayOfWeek(Timestamp))
          Case 0 : Result + "Sun"
          Case 1 : Result + "Mon"
          Case 2 : Result + "Tue"
          Case 3 : Result + "Wed"
          Case 4 : Result + "Thu"
          Case 5 : Result + "Fri"
          Case 6 : Result + "Sat"
        EndSelect
      Case 'j' : Result + Str(Day)
      Case 'l'
        Select (DayOfWeek(Timestamp))
          Case 0 : Result + "Sunday"
          Case 1 : Result + "Monday"
          Case 2 : Result + "Tuesday"
          Case 3 : Result + "Wednesday"
          Case 4 : Result + "Thursday"
          Case 5 : Result + "Friday"
          Case 6 : Result + "Saturday"
        EndSelect
      Case 'N' : Result + Str(((DayOfWeek(Timestamp) + 6) % 7) + 1)
      Case 'S'
        Select (Day)
          Case 1, 21, 31 : Result + "st"
          Case 2, 22     : Result + "nd"
          Case 3, 23     : Result + "rd"
          Default        : Result + "th"
        EndSelect
      Case 'w' : Result + Str(DayOfWeek(Timestamp))
      Case 'z' : Result + Str(DayOfYear(Timestamp)-1)
     
     
      ; Week representations
      Case 'W' : Result + "?" ; ISO week (not implemented)
     
     
      ; Month representations
      Case 'F'
        Select (Month)
          Case  1 : Result + "January"
          Case  2 : Result + "February"
          Case  3 : Result + "March"
          Case  4 : Result + "April"
          Case  5 : Result + "May"
          Case  6 : Result + "June"
          Case  7 : Result + "July"
          Case  8 : Result + "August"
          Case  9 : Result + "September"
          Case 10 : Result + "October"
          Case 11 : Result + "November"
          Case 12 : Result + "December"
        EndSelect
      Case 'm' : Result + RSet(Str(Month), 2, "0")
      Case 'M'
        Select (Month)
          Case  1 : Result + "Jan"
          Case  2 : Result + "Feb"
          Case  3 : Result + "Mar"
          Case  4 : Result + "Apr"
          Case  5 : Result + "May"
          Case  6 : Result + "Jun"
          Case  7 : Result + "Jul"
          Case  8 : Result + "Aug"
          Case  9 : Result + "Sep"
          Case 10 : Result + "Oct"
          Case 11 : Result + "Nov"
          Case 12 : Result + "Dec"
        EndSelect
      Case 'n' : Result + Str(Month)
      Case 't'
        Select (Month)
          Case 1,3,5,7,8,10,12
            Result + "31"
          Case 2
            If (Year % 400 = 0)
              Result + "29"
            ElseIf (Year % 100 = 0)
              Result + "28"
            ElseIf (Year % 4 = 0)
              Result + "29"
            Else
              Result + "28"
            EndIf
          Case 4,6,9,11
            Result + "30"
        EndSelect
       
     
      ; Year representations
      Case 'L'
        If (Year % 400 = 0)
          Result + "1"
        ElseIf (Year % 100 = 0)
          Result + "0"
        ElseIf (Year % 4 = 0)
          Result + "1"
        Else
          Result + "0"
        EndIf
      Case 'o' : Result + "?" ; ISO year (not implemented)
      Case 'Y' : Result + Str(Year)
      Case 'y' : Result + RSet(Str(Year % 100), 2, "0")
     
     
      ; Time representations
      Case 'a'
        If (Hour >= 12)
          Result + "pm"
        Else
          Result + "am"
        EndIf
      Case 'A'
        If (Hour >= 12)
          Result + "PM"
        Else
          Result + "AM"
        EndIf
      Case 'B'
        Result + RSet(Str((36000*Hour + 600*Minute + 10*Second) / 864), 3, "0")
      Case 'g' : Result + Str(((Hour + 23) % 12) + 1)
      Case 'G' : Result + Str(Hour)
      Case 'h' : Result + RSet(Str(((Hour + 23) % 12) + 1), 2, "0")
      Case 'H' : Result + RSet(Str(Hour), 2, "0")
      Case 'i' : Result + RSet(Str(Minute), 2, "0")
      Case 's' : Result + RSet(Str(Second), 2, "0")
      Case 'u' : Result + "000000" ; microseconds (not implemented)
     
     
      ; Timezone representations
      Case 'e' : Result + "?" ; Timezone identifier (not implemented)
      Case 'I' : Result + "?" ; Daylight savings flag (not implemented)
      Case 'O' : Result + GMTHour + GMTMinute
      Case 'P' : Result + GMTHour + ":" + GMTMinute
      Case 'T' : Result + "?" ; Timezone abbreviation (not implemented)
      Case 'Z' : Result + Str(FromGMT*60)
     
     
      ; Full date/time
      Case 'c' : Result + PHPFormatDate("Y-m-d\TH:i:sP")
      Case 'r' : Result + PHPFormatDate("D, d M Y H:i:s O", Timestamp)
      Case 'U' : Result + RSet(Str(Timestamp), 11, "0")
     
     
      ; Escape or pass all other characters
      Case '\' : *C + SizeOf(CHARACTER) : Result + Chr(*C\c)
      Default  : Result + Chr(*C\c)
     
    EndSelect
    *C + SizeOf(CHARACTER)
  Wend
 
  ProcedureReturn (Result)
EndProcedure











;  =======================================================================================
;-  EXAMPLE PROGRAM
;  =======================================================================================

CompilerIf (#PB_Compiler_IsMainFile)
  
  ;Debug PHPFormatDate("r", Date(2014, 8, 1, 16, 14, 0)) : End
  
  ; Create array of all valid codes
  #PHPFormats = 38
  Dim PHPFormat.s(#PHPFormats - 1)
    PHPFormat( 0) = "d"
    PHPFormat( 1) = "D"
    PHPFormat( 2) = "j"
    PHPFormat( 3) = "l"
    PHPFormat( 4) = "N"
    PHPFormat( 5) = "S"
    PHPFormat( 6) = "w"
    PHPFormat( 7) = "z"
    PHPFormat( 8) = "W"
    PHPFormat( 9) = "F"
    PHPFormat(10) = "m"
    PHPFormat(11) = "M"
    PHPFormat(12) = "n"
    PHPFormat(13) = "t"
    PHPFormat(14) = "L"
    PHPFormat(15) = "o"
    PHPFormat(16) = "Y"
    PHPFormat(17) = "y"
    PHPFormat(18) = "a"
    PHPFormat(19) = "A"
    PHPFormat(20) = "B"
    PHPFormat(21) = "g"
    PHPFormat(22) = "G"
    PHPFormat(23) = "h"
    PHPFormat(24) = "H"
    PHPFormat(25) = "i"
    PHPFormat(26) = "s"
    PHPFormat(27) = "u"
    PHPFormat(28) = "e"
    PHPFormat(29) = "I"
    PHPFormat(30) = "O"
    PHPFormat(31) = "P"
    PHPFormat(32) = "T"
    PHPFormat(33) = "Z"
    PHPFormat(34) = "c"
    PHPFormat(35) = "r"
    PHPFormat(36) = "U"
    PHPFormat(37) = "\\"
 
  ; Create window with ListIcon
  OpenWindow(0, 0, 0, 400, 600, "PHPFormatDate Demonstration", #PB_Window_ScreenCentered|#PB_Window_MinimizeGadget|#PB_Window_Invisible)
  ListIconGadget(0, 0, 0, WindowWidth(0), WindowHeight(0), "Format", 195, #PB_ListIcon_GridLines|#PB_ListIcon_FullRowSelect)
    AddGadgetColumn(0, 1, "Result", 195)
  SmartWindowRefresh(0,1)
 
  ; An example format string
  Define Main.s = "\I\t \i\s l \t\h\e jS, \o\f M Y."
    AddGadgetItem(0, 0, Main)
 
  ; Add all valid formats
  Define i.i, Event.i, Timestamp.i
  For i = 0 To #PHPFormats - 1
    AddGadgetItem(0, i+1, PHPFormat(i))
  Next i
 
  ; Timer to update
  AddWindowTimer(0, 0, 1000)
 
  Repeat
    Event = WaitWindowEvent()
   
    ; Update all fields
    If (Event = #PB_Event_Timer)
      Timestamp.i = Date()
      SetGadgetItemText(0, 0, PHPFormatDate(Main, Timestamp), 1)
      For i = 0 To #PHPFormats - 1
        SetGadgetItemText(0, i+1, PHPFormatDate(PHPFormat(i), Timestamp), 1)
      Next i
      HideWindow(0, 0)
    EndIf
  Until (Event = #PB_Event_CloseWindow)
 
CompilerEndIf

;  EOF
[/size]