NAME
Net::Nostr::Calendar - NIP-52 Calendar Events
SYNOPSIS
use Net::Nostr::Calendar;
# Date-based calendar event (kind 31922)
my $event = Net::Nostr::Calendar->date_event(
pubkey => $hex_pubkey,
identifier => 'vacation-2024',
title => 'Summer Vacation',
content => 'Two weeks off',
start => '2024-07-01',
end => '2024-07-15',
locations => ['Beach Resort'],
participants => [[$friend_pk, 'wss://relay', 'attendee']],
);
# Time-based calendar event (kind 31923)
my $event = Net::Nostr::Calendar->time_event(
pubkey => $hex_pubkey,
identifier => 'standup',
title => 'Daily Standup',
start => 1700000000,
end => 1700003600,
start_tzid => 'America/New_York',
days => [19675],
);
# Calendar (kind 31924)
my $cal = Net::Nostr::Calendar->calendar(
pubkey => $hex_pubkey,
identifier => 'personal',
title => 'Personal Calendar',
events => [
["31922:$pk:vacation-2024", 'wss://relay'],
],
);
# RSVP (kind 31925)
my $rsvp = Net::Nostr::Calendar->rsvp(
pubkey => $hex_pubkey,
identifier => 'rsvp-1',
event_coord => "31922:$organizer_pk:vacation-2024",
status => 'accepted',
fb => 'busy',
);
# Parse any calendar event
my $parsed = Net::Nostr::Calendar->from_event($event);
# Validate
Net::Nostr::Calendar->validate($event);
DESCRIPTION
Implements NIP-52 (Calendar Events). Four addressable event kinds are used:
Date-Based Calendar Event (kind 31922) - All-day or multi-day events where time and time zone hold no significance.
Time-Based Calendar Event (kind 31923) - Events spanning between a start time and end time.
Calendar (kind 31924) - A collection of calendar events.
Calendar Event RSVP (kind 31925) - Attendance response to a calendar event.
All four kinds are addressable and deletable per NIP-09.
Common tags for calendar events
Both date-based and time-based calendar events share these tags:
d(required) - unique identifiertitle(required) - title of the eventsummary(optional) - brief descriptionimage(optional) - URL of an imagelocation(optional, repeated) - location stringg(optional) - geohash for searchable locationp(optional, repeated) - participant pubkey, relay URL, and rolet(optional, repeated) - hashtagr(optional, repeated) - reference URLa(repeated) - reference to kind 31924 calendar
The deprecated name tag is mapped to title when parsing if title is not present.
CONSTRUCTOR
new
my $cal = Net::Nostr::Calendar->new(
identifier => 'meeting',
title => 'Team Meeting',
);
Creates a new Net::Nostr::Calendar object. Croaks on unknown arguments. Array fields default to []. description defaults to ''.
CLASS METHODS
date_event
my $event = Net::Nostr::Calendar->date_event(
pubkey => $hex_pubkey, # required
identifier => $id, # required (d tag)
title => $title, # required (title tag)
start => 'YYYY-MM-DD', # required
end => 'YYYY-MM-DD', # optional
content => $description, # optional, defaults to ''
summary => $text, # optional
image => $url, # optional
locations => [$location], # optional
geohash => $geohash, # optional
participants => [[$pk, $relay, $role]], # optional
hashtags => [$tag], # optional
references => [$url], # optional
calendars => [$coord], # optional (a tags)
created_at => time(), # optional
);
Creates a kind 31922 date-based calendar Net::Nostr::Event. The start date is inclusive and in ISO 8601 format (YYYY-MM-DD). The end date is exclusive. If end is omitted, the event ends on the same date as start. start must be less than end if both are present (enforced by "validate").
time_event
my $event = Net::Nostr::Calendar->time_event(
pubkey => $hex_pubkey, # required
identifier => $id, # required (d tag)
title => $title, # required (title tag)
start => $unix_timestamp, # required
end => $unix_timestamp, # optional
start_tzid => 'America/New_York', # optional (IANA TZ)
end_tzid => 'America/New_York', # optional (IANA TZ)
days => [$day_number], # required per spec (D tags)
content => $description, # optional, defaults to ''
summary => $text, # optional
image => $url, # optional
locations => [$location], # optional
geohash => $geohash, # optional
participants => [[$pk, $relay, $role]], # optional
hashtags => [$tag], # optional
references => [$url], # optional
calendars => [$coord], # optional (a tags)
created_at => time(), # optional
);
Creates a kind 31923 time-based calendar Net::Nostr::Event. The start timestamp is inclusive (Unix seconds). The end timestamp is exclusive. If end is omitted, the event ends instantaneously. start must be less than end if both are present (enforced by "validate"). days are day-granularity timestamps (D tags) calculated as floor(unix_seconds / 86400). The spec requires at least one D tag (enforced by "validate").
calendar
my $event = Net::Nostr::Calendar->calendar(
pubkey => $hex_pubkey, # required
identifier => $id, # required (d tag)
title => $title, # required (title tag)
content => $description, # optional, defaults to ''
events => [[$coord, $relay]], # optional (a tags)
);
Creates a kind 31924 calendar Net::Nostr::Event. events is an arrayref of arrayrefs, each containing a calendar event coordinate and optional relay URL.
rsvp
my $event = Net::Nostr::Calendar->rsvp(
pubkey => $hex_pubkey, # required
identifier => $id, # required (d tag)
event_coord => $coord, # required (a tag)
status => 'accepted', # required
event_relay => $url, # optional (a tag relay)
event_id => $eid, # optional (e tag)
event_id_relay => $url, # optional (e tag relay)
fb => 'busy', # optional (free/busy)
event_author => $pk, # optional (p tag)
event_author_relay => $url, # optional (p tag relay)
content => $note, # optional, defaults to ''
);
Creates a kind 31925 RSVP Net::Nostr::Event. status must be accepted, declined, or tentative. The fb tag is automatically omitted when status is declined.
from_event
my $cal = Net::Nostr::Calendar->from_event($event);
Parses a kind 31922, 31923, 31924, or 31925 event into a Net::Nostr::Calendar object. Returns undef for unrecognized kinds. Handles the deprecated name tag (mapped to title if title is absent).
validate
Net::Nostr::Calendar->validate($event);
Validates a NIP-52 event. Croaks if:
Kind is not 31922, 31923, 31924, or 31925
Kind 31922/31923 missing
d,title, orstarttagKind 31922/31923
startis not less thanend(whenendis present)Kind 31923 missing
DtagKind 31924 missing
dortitletagKind 31925 missing
d,a, orstatustagKind 31925
statusis notaccepted,declined, ortentative
Returns 1 on success.
ACCESSORS
identifier
The d tag value.
title
The calendar event or calendar title.
description
The event content. Defaults to ''.
start
The start date (YYYY-MM-DD for kind 31922) or Unix timestamp string (for kind 31923).
end
The end date or Unix timestamp string, or undef.
summary
Brief description, or undef.
image
Image URL, or undef.
locations
Arrayref of location strings. Defaults to [].
geohash
Geohash string, or undef.
participants
Arrayref of arrayrefs, each containing pubkey, optional relay URL, and optional role. Defaults to [].
hashtags
Arrayref of hashtag strings. Defaults to [].
references
Arrayref of reference URL strings. Defaults to [].
calendars
Arrayref of kind 31924 calendar coordinates (from a tags in calendar events). Defaults to [].
calendar_events
Arrayref of arrayrefs, each containing a calendar event coordinate and optional relay URL (from a tags in calendars). Defaults to [].
start_tzid
IANA Time Zone Database identifier for the start time (kind 31923 only).
end_tzid
IANA Time Zone Database identifier for the end time (kind 31923 only).
days
Arrayref of day-granularity timestamp strings (D tags, kind 31923 only). Defaults to [].
event_coord
The calendar event coordinate (a tag value, RSVP only).
event_id
The specific calendar event revision ID (e tag value, RSVP only).
status
RSVP status: accepted, declined, or tentative.
fb
Free/busy indicator: free or busy. Must be omitted or ignored if status is declined.
event_author
Pubkey of the calendar event author (RSVP only).