gmlscripts / scripts

GMLscripts.com scripts for GameMaker
Other
76 stars 14 forks source link

Possible problem with ISO 8601 week number and year number #11

Open xotmatrix opened 7 years ago

xotmatrix commented 7 years ago

re: date_format()

This was a pain in the neck to originally research and code until I realized that GM did most of the work already with its week number (which appeared to be ISO 8601 compliant). I saw an example tonight that may show ISO 8601 week numbers and year numbers are not being calculated corrected here. Need to do some more research.

https://derickrethans.nl/iso-8601-weeks.html

xotmatrix commented 3 years ago

This continues to be a problem in GMS2.3 and is still being investigated.

Here also is an early version of this function written in the GM6 days with a complicated ISO 8601 week calculation. I don't know if it worked right.

/*
**  Usage:
**      date_format(format,datetime)
**
**  Arguments:
**      format      string controlling date formatting
**      datetime    date-time value (optional)
**
**  Returns:
**      a string formatted according to the given format string
**      using the given date-time value or the current local time
**      if no date-time is given
**
**  Day format characters:
**      d - day of the month, 2 digits with leading zeros; 01 through 31
**      D - day of the week, textual, 3 letters; Fri
**      j - day of the month without leading zeros; 1 through 31
**      l - day of the week, textual, long; Friday
**      N - ISO 8601 day number of the week; 1 (Monday) through 7 (Sunday)
**      S - English ordinal suffix, textual, 2 characters; st, nd, rd, th
**      w - day of the week, numeric, 0 (Sunday) through 6 (Saturday)
**      z - day of the year (starting from zero); 0 through 365
**
**  Week format characters:
**      W - ISO 8601 week number of year, weeks starting on Monday; 42
**
**  Month format characters:
**      F - month, textual, long; January
**      m - month; 01 through 12
**      M - month, textual, 3 letters; Jan
**      n - month without leading zeros; 1 through 12
**      t - number of days in the given month; 28 through 31
**
**  Year format characters:
**      L - whether it is a leap year; 0 or 1
**      o - ISO 8601 year, like Y unless ISO week belongs to prev or next year; 2008
**      Y - year, 4 digits; 1999
**      y - year, 2 digits; 99
**
**  Time format characters:
**      a - lowercase Ante meridiem and Post meridiem; am or pm
**      A - uppercase Ante meridiem and Post meridiem; AM or PM
**      B - Swatch Internet time; 000 through 999
**      g - hour, 12-hour format without leading zeros; 1 through 12
**      G - hour, 24-hour format without leading zeros; 0 through 23
**      h - hour, 12-hour format; 01 through 12
**      H - hour, 24-hour format; 00 through 23
**      i - minutes, with leading zero; 00 through 59
**      s - seconds, with leading zero; 00 through 59
**
**  Full Date/Time format characters:
**      c - ISO 8601 date
**      r - RFC 2822 formatted data
**      U - seconds since the Unix epoch
**
**      \ - escape letters which should be literal, not interpreted
**
**  Exaples:
**      date_format("l jS of F Y h:i:s A") == "Sunday 4th of May 2008 05:45:34 PM"
**      date_format('\I\t \i\s \t\h\e zS \d\a\y.') == "It is the 124th day."
**
**  GMLscripts.com
*/
{
    var str,dat,out,day,month,year,weekday,second,minute,hour24,hour12,i,c;
    str = argument0;
    dat = argument1;
    out = "";
    if (dat == 0) dat = date_current_datetime();
    day     = date_get_day(dat);
    month   = date_get_month(dat);
    year    = date_get_year(dat);
    weekday = date_get_weekday(dat);
    second  = date_get_second(dat);
    minute  = date_get_minute(dat);
    hour24  = date_get_hour(dat);
    hour12  = ((hour24+23) mod 12)+1;
    for (i=1; i<=string_length(str); i+=1) {
        c = string_char_at(str,i);
        switch (c) {
        case "F":
            switch (month) {
            case 1:  out += "January";   break;
            case 2:  out += "February";  break;
            case 3:  out += "March";     break;
            case 4:  out += "April";     break;
            case 5:  out += "May";       break;
            case 6:  out += "June";      break;
            case 7:  out += "July";      break;
            case 8:  out += "August";    break;
            case 9:  out += "September"; break;
            case 10: out += "October";   break;
            case 11: out += "November";  break;
            case 12: out += "December";  break;
            }
            break;
        case "M":
            switch (month) {
            case 1:  out += "Jan"; break;
            case 2:  out += "Feb"; break;
            case 3:  out += "Mar"; break;
            case 4:  out += "Apr"; break;
            case 5:  out += "May"; break;
            case 6:  out += "Jun"; break;
            case 7:  out += "Jul"; break;
            case 8:  out += "Aug"; break;
            case 9:  out += "Sep"; break;
            case 10: out += "Oct"; break;
            case 11: out += "Nov"; break;
            case 12: out += "Dec"; break;
            }
            break;
        case "l":
            switch (weekday) {
            case 1: out += "Sunday";    break;
            case 2: out += "Monday";    break;
            case 3: out += "Tuesday";   break;
            case 4: out += "Wednesday"; break;
            case 5: out += "Thursday";  break;
            case 6: out += "Friday";    break;
            case 7: out += "Saturday";  break;
            }
            break;
        case "D":
            switch (weekday) {
            case 1: out += "Sun"; break;
            case 2: out += "Mon"; break;
            case 3: out += "Tue"; break;
            case 4: out += "Wed"; break;
            case 5: out += "Thu"; break;
            case 6: out += "Fri"; break;
            case 7: out += "Sat"; break;
            }
            break;
        case "S":
            if (day >= 10 && day <= 20) out += "th";
            else if ((day mod 10) == 1) out += "st";
            else if ((day mod 10) == 2) out += "nd";
            else if ((day mod 10) == 3) out += "rd";
            else                        out += "th";
            break;
        case "Y": out += string(year); break;
        case "y": out += string_copy(string(year),3,2); break;
        case "m": if (month < 10) out += "0";
        case "n": out += string(month); break;
        case "d": if (day < 10) out += "0";
        case "j": out += string(day); break;
        case "H": if (hour24 < 10) out += "0";
        case "G": out += string(hour24); break;
        case "h": if (hour12 < 10) out += "0";
        case "g": out += string(hour12); break;
        case "i": if (minute < 10) out += "0"; out += string(minute); break;
        case "s": if (second < 10) out += "0"; out += string(second); break;
        case "a": if (hour24 < 12) out += "am" else out += "pm"; break;
        case "A": if (hour24 < 12) out += "AM" else out += "PM"; break;
        case "U": out += string(round(date_second_span(dat,25568.8333))); break;
        case "z": out += string(date_get_day_of_year(dat)-1); break;
        case "t": out += string(date_days_in_month(month)); break;
        case "L": out += string(date_leap_year(dat)); break;
        case "w": out += string(weekday-1); break;
        case "N": out += string(((weekday+5) mod 7)+1); break;
        case "W":
            // 1+INT((A1-DATE(YEAR(A1+4-WEEKDAY(A1+6)),1,5)+WEEKDAY(DATE(YEAR(A1+4-WEEKDAY(A1+6)),1,3)))/7)
            // 1 + INT(
            //           (
            //                A1 
            //                - DATE(
            //                        YEAR(A1+4-WEEKDAY(A1+6)),
            //                        1,
            //                        5
            //                  )   
            //                + WEEKDAY(
            //                           DATE(
            //                                 YEAR(A1+4-WEEKDAY(A1+6)),
            //                                 1,
            //                                 3
            //                           )
            //                  )
            //           ) 
            //           / 7
            //    )

            out += string(
                1 + floor(
                    ( // date_day_span(dat,date_create_date(date_get_year(date_inc_day(dat,4-date_get_weekday(date_inc_day(dat,6)))),1,5))
                        date_day_span(dat,
                            date_create_date(
                                date_get_year(date_inc_day(dat,4-date_get_weekday(date_inc_day(dat,6)))),
                                1,
                                5
                            )
                        )
                      + date_get_weekday(
                                date_create_date(
                                    date_get_year(date_inc_day(dat,4-date_get_weekday(date_inc_day(dat,6)))),
                                    1,
                                    3
                                )
                        )
                    )
                    /7
                )
            );
            break;
        default:  out += c; break;
        }
    }
    return out;

Source: E:\_xotgames\_prototypes\datetime-functions\date_format.gm6

xotmatrix commented 3 years ago

ISO 8601 year is also not working right.

        case "o":
            if (month ==  1 && day <=  3 && week != 1) { out += string(year-1); break; }
            if (month == 12 && day >= 29 && week == 1) { out += string(year+1); break; }