Formatting Dates

Obviously you’re welcome to make your own for your own use, but the names of the handlers — rfc3339FromDate: and dateFromRfc3339String: — imply conformance to RFC 3339.

One of the places I think people might want to use these sorts of handlers is in parsing JSON. There’s no standard defined for JSON dates, but many claim to be using RFC3339.

However, many are actually using "yyyy'-'MM'-'dd'T'HH':'mm':'ssXX" rather than "yyyy'-'MM'-'dd'T'HH':'mm':'ssXXX" (the difference is that RFC 3339 specifies time zones other than GMT as -06:00 rather than -0600). But as long as you stick to GMT-based values, the difference doesn’t matter.

The joy of standards that aren’t…

1 Like

Shane, I’m assuming that the locale ID will need to vary with the country. Is this correct?
If so, two questions:

  1. Can get get the script user’s locale ID for use in this statement?
  2. If we want to force the locale to be elsewhere, where can we get the list of locales by country?

I’ve done quite a bit of searching, but as usual Apple has not seen fit to publish lists of actual parameter values, at least not so I can find them. :wink:

It was easy to find this: localeWithLocaleIdentifier:

but no parameter values seem to be available.

Thanks.

Not for ISO 8601 and RFC 3339 formats. The reason for specifying “en_US_POSIX” is that if you leave the user’s locale (which will be the default if you don’t specify a locale), formatters can overrule the format string. In particular, HH can be interpreted differently depending on the locale’s settings.

Normally you can use:

current application's NSLocale's currentLocale()

Use:

current application's NSLocale's availableLocaleIdentifiers()

To get the identifier of the current locale:

current application's NSLocale's currentLocale()'s localeIdentifier()

So:

current application's NSLocale's localeWithLocaleIdentifier:"en_AU" -- for example
2 Likes

Hey Mark @alldritt, how do you use your handlers to get a date string from a custom (not now) date?
Also, how do you convert an AppleScript date to a NSDate in 10.12+, specifically Mojave?

This fails:

use framework "Foundation"
use scripting additions

set dateStr to "6/1/2019"
set myDate to date dateStr
###  set theDate to current application's NSDate's |date|() -- now

### This Fails ###
#  ERROR:  Can’t get myDate of NSDate.
set theDate to current application's NSDate's myDate
set dateString to my rfc3339FromDate:theDate

--> "2017-11-27T06:38:31Z"


on rfc3339FromDate:aDate
  set theFormatter to current application's NSDateFormatter's new()
  theFormatter's setLocale:(current application's NSLocale's localeWithLocaleIdentifier:"en_US_POSIX")
  theFormatter's setTimeZone:(current application's NSTimeZone's timeZoneWithAbbreviation:"GMT") -- skip for local time
  theFormatter's setDateFormat:"yyyy'-'MM'-'dd'T'HH':'mm':'ssXXX"
  return (theFormatter's stringFromDate:aDate) as text
end rfc3339FromDate:

You can pass any date — an NSDate or an AppleScript date — in 10.11 or later.

A variant, using NSISO8601DateFormatter and the NSISO8601DateFormatWithInternetDateTime option.

( Perhaps Shane will know what versions of macOS support this, and what its limitations, if any, might be )

use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

-- iso8601StringFromDate :: Date -> String
on iso8601StringFromDate(dte)
    tell current application
        set fmt to (its NSISO8601DateFormatWithInternetDateTime as integer)
        tell init() of alloc of its NSISO8601DateFormatter
            set formatOptions to fmt
            stringFromDate_(dte) as string
        end tell
    end tell
end iso8601StringFromDate

-- dateFromiso8601String :: String -> Date
on dateFromiso8601String(strISO8601)
    tell current application
        set fmt to (its NSISO8601DateFormatWithInternetDateTime as integer)
        tell init() of alloc of its NSISO8601DateFormatter
            set formatOptions to fmt
            dateFromString_(strISO8601) as date
        end tell
    end tell
end dateFromiso8601String


on run
    dateFromiso8601String(iso8601StringFromDate(current date))
end run

NSISO8601DateFormatter requires 10.12 or later. But there was a glitch in the .bridgesupport file in 10.12 where the enums for it were left out, so you either have to define their values yourself in the script via properties (Script Debugger code-completion includes them in 10.12), or use the raw enums. Otherwise it’s effectively 10.13 or later.

I apologize Shane but under 10.13.6 the code posted by JTMichaelTX fails with error "Il est impossible d’obtenir myDate of NSDate.
If I replace
set theDate to current application’s NSDate’s myDate
by
set theDate to myDate
The script reach its end.

myDate is reported as : (date dimanche 6 janvier 2019 à 00:00:00) which is correct.

The final dateString is set to : “2019-01-05T23:00:00Z” which seems curious from my point of view.

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) jeudi 25 juillet 2019 15:21:40

That’s right — you only need to involve current application’s NSDate for Cocoa dates, not AppleScript dates. Under 10.11 and greater, you can just pass an AppleScript date as-is.

In what way?

I wonder why 6 janvier 00h00 becomes 5 janvier 23h00.

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) jeudi 25 juillet 2019 16:38:05

Oops. Now I understand, the result is the Greenwich time.

If JTMichaelTX really need to build an NSDate from as Applescript date,he may use a handler given by Shane in Everyday AppleScriptObjC 3ed

use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

on makeNSDateFrom:theASDate
	set {theYear, theMonth, theDay, theSeconds} to theASDate's {year, month, day, time}
	set theCalendar to current application's NSCalendar's currentCalendar()
	set newDate to theCalendar's dateWithEra:1 |year|:theYear |month|:(theMonth as integer) |day|:theDay hour:0 minute:0 |second|:theSeconds nanosecond:0
	--log (newDate's |description|() as text)
	return newDate
end makeNSDateFrom:
set dateStr to "6/1/2019"
set theDate to date dateStr
log theDate (*date dimanche 6 janvier 2019 à  00:00:00*)
set theNSDate to its makeNSDateFrom:theDate
log (theNSDate's |description|() as text) (*2019-01-05 23:00:00 +0000*)

It seems that I forgot the correct syntax to encapsulate code here.

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) jeudi 25 juillet 2019 18:54:22

Three backquotes on a line before and after. I’ve fixed it above.

Although there’s no stringWithString: or arrayWithArray: style method for converting dates, as long as you’re running 10.11 or later, you can use this:

set theDate to current application's NSDate's dateWithTimeInterval:0 sinceDate:ASOrNSDate

Thanks Shane for both messages.

Just to be sure, are you speaking of the character whose ID is 8216 or the one whose ID is 8217?

I ask because Apple doesn’t use your naming.
character ID 8216 is named LEFT SINGLE QUOTATION MARK
character ID 8217 is named RIGHT SINGLE QUOTATION MARK

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) vendredi 26 juillet 2019 10:37:07

The one whose id is 96. You should be able to go back and click the pencil icon to edit your message — that will show exactly.

Thanks.
It’s named GRAVE ACCENT in the tool displaying the Emojis and symbols.

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) vendredi 26 juillet 2019 12:01:41

Yes, that’s the correct name. But inprogramming it’s generally called a backtick or backquote. See https://en.wikipedia.org/wiki/Grave_accent:

Some variations of Markdown support “fenced code blocks” that span multiple lines of code, starting (and ending) with three backticks in a row (```).

Thanks.
Now I have stored the info in a text file available on my desktop.

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) vendredi 26 juillet 2019 15:39:35

Revisiting this, I’m try to find out if there’s a simple way to extract the relative day from a future date.

For example, based on the current date (10/4/24):

Oct. 3, 2024 --Yesterday
Oct. 4, 2024 – Today
Oct. 5, 2024 – Tomorrow

It looks like that’s been solved and if so it would be much better than writing an appleScript handler to do it.

Never mind, I found it with some googling.

use AppleScript version "2.4"
use framework "Foundation"
use scripting additions
set theDate to ((current date) - 1 * days)
set dateFormat to current application's NSDateFormatter's alloc()'s init()
dateFormat's setDateStyle:(current application's NSDateFormatterLongStyle)
dateFormat's setTimeStyle:(current application's NSDateFormatterMediumStyle)
dateFormat's setDoesRelativeDateFormatting:true
set theDay to (dateFormat's stringFromDate:theDate) as text

In fact, I found it here, but it didn’t show up when I searched SD Forums…

(Thanks again, Shane!)