Skip to content

Instantly share code, notes, and snippets.

@choonkeat
Created September 12, 2022 10:29
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save choonkeat/4816492d4f75b389beefc197d4f7f83f to your computer and use it in GitHub Desktop.
very rudimentary iCalendar format support in elm
module ICal exposing
( VAlarmAction(..)
, VAlarmTrigger(..)
, VCalendar(..)
, VEvent(..)
, VEventProp(..)
, VEventStatusValue(..)
, eventPropString
, eventString
, string
)
{-| Build VCalendar values and generate string out of it
Refer to <https://www.ietf.org/rfc/rfc2445.txt>
<https://www.kanzaki.com/docs/ical/>
Example:
let
cal =
VCalendar
[ VEvent
[ VEventUID "unique123"
, VEventSummary "Title"
, VEventDescription "Lorem ipsum"
, VEventLocation "Conference Room - F123, Bldg. 002"
, VEventDTStart startTime
, VEventDTEnd endTime
, VEventURL "https://www.kanzaki.com/docs/ical/"
, VEventStatus VEventStatusConfirmed
, VAlarm (VAlarmTrigger "-PT1H") "Remember the milk!" VAlarmActionDisplay
]
]
in
ICal.string cal
-}
import DateFormat
import Time
type VCalendar
= VCalendar (List VEvent)
type VEvent
= VEvent (List VEventProp)
type VEventProp
= VEventUID String
| VEventSummary String
| VEventDescription String
| VEventLocation String
| VEventDTStart Time.Posix
| VEventDTEnd Time.Posix
| VEventURL String
| VEventStatus VEventStatusValue
| VAlarm VAlarmTrigger String VAlarmAction
type VEventStatusValue
= VEventStatusTentative
| VEventStatusConfirmed
| VEventStatusCancelled
type VAlarmTrigger
= VAlarmTrigger String
type VAlarmAction
= VAlarmActionAudio
| VAlarmActionDisplay
| VAlarmActionEmail
| VAlarmActionProcedure
string : VCalendar -> String
string (VCalendar events) =
String.join "\n" ("BEGIN:VCALENDAR" :: List.map eventString events) ++ "\nEND:VCALENDAR"
eventString : VEvent -> String
eventString (VEvent props) =
String.join "\n" ("BEGIN:VEVENT" :: List.map eventPropString props) ++ "\nEND:VEVENT"
eventPropString : VEventProp -> String
eventPropString prop =
case prop of
VEventUID s ->
"UID:" ++ s
VEventSummary s ->
"SUMMARY:" ++ s
VEventDescription s ->
"DESCRIPTION:" ++ s
VEventLocation s ->
"LOCATION:" ++ s
VEventDTStart posixTime ->
"DTSTART:" ++ dtString posixTime
VEventDTEnd posixTime ->
"DTEND:" ++ dtString posixTime
VEventURL s ->
"URL:" ++ s
VEventStatus s ->
"STATUS:" ++ statusString s
VAlarm (VAlarmTrigger ts) s action ->
String.join "\n"
[ "BEGIN:VALARM"
, "TRIGGER:" ++ ts
, "DESCRIPTION:" ++ s
, "ACTION:" ++ actionString action
, "END:VALARM"
]
--
dtString : Time.Posix -> String
dtString posixTime =
DateFormat.format
[ DateFormat.yearNumber
, DateFormat.monthFixed
, DateFormat.dayOfMonthFixed
, DateFormat.text "T"
, DateFormat.hourMilitaryFixed
, DateFormat.minuteFixed
, DateFormat.text "00Z" --forcing `00` seconds instead of DateFormat.secondFixed
]
Time.utc
posixTime
statusString : VEventStatusValue -> String
statusString status =
case status of
VEventStatusTentative ->
"TENTATIVE"
VEventStatusConfirmed ->
"CONFIRMED"
VEventStatusCancelled ->
"CANCELLED"
actionString : VAlarmAction -> String
actionString action =
case action of
VAlarmActionAudio ->
"AUDIO"
VAlarmActionDisplay ->
"DISPLAY"
VAlarmActionEmail ->
"EMAIL"
VAlarmActionProcedure ->
"PROCEDURE"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment