# encoding: ascii
# api: powershell
# title: New-Event
# description: A PowerShell client for NaturalInputs.com to parse natural language dates into (optionally recurring) calendar event objects.
# version: 1.2
# type: function
# author: Joel Bennett
# license: CC0
# function: New-Event
# x-poshcode-id: 3059
# x-archived: 2011-11-29T18:12:54
# x-published: 2011-11-20T21:54:00
#
#
function New-Event {
<#
.Synopsis
Generates a new event from a plain English string
.Description
Takes a plain English date-time string like "Scrum every day at 9am" or "Lunch every other Tuesday at noon" and turns it into an event object (see notes).
.Example
New-Event Lunch every other Friday at 11:45
.Example
New-Event Lunch at noon on Christmas
.Notes
v 1.2 Supports resolving common calendar holidays
But NaturalInputs' API still can't do relative dates, so:
You can now schedule "Lunch at noon on Easter" but not "Lunch at noon the Sunday before Memorial Day" or "Dinner at 6 PM the day after Christmas"
#>
param(
[Parameter(ValueFromRemainingArguments=$true, ValueFromPipeline=$true, Position=0)]
[string]$query
,
[DateTime]$currentTime = $([DateTime]::Now)
,
[ValidateSet("Canada", "GreatBritain", "IrelandNorthern", "IrelandRepublicOf", "Scotland", "UnitedStates")]
[String]$Country = "UnitedStates"
)
begin {
$wc = New-Object System.Net.WebClient
$time = $currentTime.ToString("yyyyMMddThhmmss")
if(!$global:Holidays) {
$service = New-WebServiceProxy http://www.holidaywebservice.com/HolidayService_v2/HolidayService2.asmx
$global:Holidays = $service.GetHolidaysForYear( $Country, $currentTime.Year )
$global:Holidays += $service.GetHolidaysForYear( $Country, $currentTime.Year + 1 )
}
$HolidayKeys = @{}
foreach($holiday in $global:Holidays) {
$key = $holiday.Descriptor -replace " Day" -replace "'s" -replace " Birthday"
$key = $key.Trim()
$HolidayKeys[$key] += @($holiday)
}
}
process {
foreach($key in $HolidayKeys.Keys) {
$keyPattern = [System.Text.RegularExpressions.Regex]::Escape($key)
if($query -match $keyPattern ) {
Write-Verbose $keyPattern
if($query -match "next\s+$keyPattern") {
$currentTime = $currentTime.AddYears(1)
}
if($query -match "$keyPattern.*observed") {
$holiday = $HolidayKeys[$key] | Where-Object { $_.DateType -match "observed" -and ($_.Date.Year -eq $currentTime.Year) } | Select -First 1
} else {
$holiday = $HolidayKeys[$key] | Where-Object { $_.DateType -match "actual" -and ($_.Date.Year -eq $currentTime.Year) } | Select -First 1
}
$query = $query -replace "(next\s+)?$keyPattern(.*observed)?", $Holiday.Date.ToString("d",$Culture)
break
}
}
Write-Verbose "Query: $query"
$query = [System.Web.HttpUtility]::UrlEncode( $query )
[xml]$event = $wc.DownloadString( "http://naturalinputs.com/query?t=$time&q=$query" )
Write-Verbose "Response: $($event.OuterXml)"
foreach($r in $event.naturalinputsresponse) {
foreach($o in $r.occurrence) {
if($o.start_date) {
if($o.start_time) {
$startdate = Get-Date ([DateTime]::ParseExact( ("{0}T{1}" -f $o.start_date, $o.start_time), "yyyyMMddTHH:mm:ss", $null)) -DisplayHint "Date"
$starttime = Get-Date ([DateTime]::ParseExact( ("{0}T{1}" -f $o.start_date, $o.start_time), "yyyyMMddTHH:mm:ss", $null)) -DisplayHint "Time"
} else {
$startdate = Get-Date ([DateTime]::ParseExact( $o.start_date, "yyyyMMdd", $null)) -DisplayHint "Date"
$starttime = $null
}
} elseif ($o.start_time) {
$startdate = $null
$starttime = Get-Date $o.start_time -DisplayHint "Time"
}
if($o.end_date) {
if($o.end_time) {
$enddate = Get-Date ([DateTime]::ParseExact( ("{0}T{1}" -f $o.end_date, $o.end_time), "yyyyMMddTHH:mm:ss", $null)) -DisplayHint "Date"
$endtime = Get-Date ([DateTime]::ParseExact( ("{0}T{1}" -f $o.end_date, $o.end_time), "yyyyMMddTHH:mm:ss", $null)) -DisplayHint "Time"
} else {
$enddate = Get-Date ([DateTime]::ParseExact( $o.end_date, "yyyyMMdd", $null)) -DisplayHint "Date"
$endtime = $null
}
} elseif ($o.end_time) {
if($o.start_date) {
$enddate = $null
$endtime = Get-Date ([DateTime]::ParseExact( ("{0}T{1}" -f $o.start_date, $o.end_time), "yyyyMMddTHH:mm:ss", $null)) -DisplayHint "Time"
} else {
$enddate = $null
$endtime = Get-Date $o.end_time -DisplayHint "Time"
}
}
New-Object PSObject -Property @{
Name=$r.message
Type=$o.type
DayOfWeek=$o.day_of_week
WeekOfMonth=$o.week_of_month
DateOfMonth=$o.date_of_month
Interval=$o.interval
StartDate=$startdate
StartTime=$starttime
EndDate=$enddate
EndTime=$endtime
# Xml=$event
} | Add-Member ScriptProperty TimeUntil { $this.StartDate - (Get-Date) } -Passthru
}
}
}
}