Applescript: Convert date into something useful, then perform calculation - datetime

I'm trying to create an applescript script that will take a date in the form:
02/20/99
Then, subtract 5 days from the date, and return a date like this:
02/15/99
Here's the basic applescript I have, but, obviously, I'm missing the logic around converting the date into something that I can manipulate (and returning it to something readable by humans).
set itemPath to quoted form of POSIX path of theFile
set dateString to do shell script "awk 'NR == 10 {print $3}' " & itemPath & " -"
set myDueDate to dateString - (5 * days)
set theTask to "Pay AMEX bill"
tell application "OmniFocus"
tell front document
set theContext to first flattened context where its name = "OFFICE"
set theProject to first flattened context where its name = "Bookkeeping - PMS"
tell theProject to make new task with properties {name:theTask, context:theContext, due date:myDueDate}
end tell
end tell
Thanks in advance!

I think these lines should be sufficient for what you need:
set dateString to "02/20/99"
set thisDate to date dateString
set fiveDaysEarlier to thisDate - 5 * days
log date string of fiveDaysEarlier
log short date string of fiveDaysEarlier
This page has some more examples of the coercions supported when converting strings to objects of date class:
AppleScript Class Reference: date
Also, it probably goes without saying, but the string "02/20/99" is not Y2k compliant, so guesses will have to be made somewhere as to which century this date lies in.

If you get error "FileMaker Pro got an error: Object not found." number -1728, add my before date. e.g,
set thisDate to my date dateString.
When working inside a tell, I think it needs to access methods outside the tell's scope.

Related

MSACCESS Form VBA Open Where Clause - US v AU Date Formatting

Morning all,
This should be a simple fix and I have searched around and found things that appear they should work, but they don't seem to though...
So - it's a simple "Open this form and show only records from This date" function and, you guessed it, good ol' US of A date formatting is the problem and no matter which way I try it nothing is solving the problem...
So - here's the form code...
DoCmd.OpenForm "frm_Prod_Runs_Edit_List", , , "# " & NEWDATE & " #"
to find NEWDATE...
I strip the date components from a couple of combo boxes (CBOYear & CBOMonth) and a field that represents the day of the month (data will be in the format "1st" or "2nd" etc...)
I concatenate the individual components...
NEWDATE = DateSerial(TempYear, TempMonth, TempDate)
A msgbox NEWDATE popup results in the correct data (ie 1/3/18)
But when I run the code it either selects everything or nothing... the only time the function works is when the day field is 13 or higher (ie 13/3/18) - thus it can determine the correct format to work with.
I'm sure the correct answer is already here somewhere - the correct question however may be something I have not thought to search for.
I have tried to use DATEVALUE() before and within the form open code. I have tried to hard code the US format to see if that works...
DoCmd.OpenForm "frm_Prod_Runs_Edit_List", , , "#3/1/18#"
No good... shows all records - same if I hard code for the AU format #1/3/18#
My PC is set up for AU format dd/mm/yy
So... Which function do I need to use to convert the AU Date string into US Date string prior to calling the Openform, so the correct records open? OR is there a better way to write the WHERE clause in the Docmd line to achieve this result? - Or do I need to reset all my date fields to US format and convert them back to AU on the forms only?
Thanks for the feedback...
In VBA and VB6, date-literals using the # syntax are always in M/dd/yyyy format, regardless of the user's date format settings. This is a legacy of VBA/VB6's development in the USA before localization was a concern (and the USA is the only country to use the illogical MM/dd/yyyy format).
Note it's M/dd/yyyy and not MM/dd/yyyy - so omit any leading zeroes.
This is documented here: https://learn.microsoft.com/en-us/dotnet/visual-basic/language-reference/data-types/date-data-type
The same rule also applies to date-literals in Access SQL (not the same thing as VBA/VB6). Fortunately in SQL Server you always use the ISO 8601 yyyy-MM-dd format in quotes... shame about Access though.
You simply need a properly formatted string expression for your date value - and the correct syntax:
Dim NEWDATE As Date
Dim WhereCondition As String
NEWDATE = DateSerial(TempYear, TempMonth, TempDate)
WhereCondition = "[NameOfYourDateField] = #" & Format(NEWDATE, "yyyy\/mm\/dd") & "#"
DoCmd.OpenForm "frm_Prod_Runs_Edit_List", , , WhereCondition
Your first problem is that you're not comparing NewDate to something.
Your second problem is that you're using string concatenation to filter by a date, and that results in the wrong date.
You can view this answer for the different ways to use parameters in Access.
Your final code should probably look something like this:
NEWDATE = DateSerial(TempYear, TempMonth, TempDate)
DoCmd.SetParameter("NewDateParam", NEWDATE)
DoCmd.OpenForm "frm_Prod_Runs_Edit_List", , , "SomeDateField = NewDateParam"
Or, if there might be time stored with the date:
NEWDATE = DateSerial(TempYear, TempMonth, TempDate)
DoCmd.SetParameter("NewDateParam", NEWDATE)
DoCmd.OpenForm "frm_Prod_Runs_Edit_List", , , "SomeDateField - NewDateParam < 1"

USQL reading last n days when file name pattern does not have day part

In data lake I have file names with pattern yyyyMM_data.csv. Now I want to read previous 3 days data. I am using below code -
DECLARE #ReportDate DateTime= DateTime.Parse("05/08/2017");
DECLARE #FeatureSummaryInput string=#"/FolderPath/{InputFileDate:yyyy}{InputFileDate:MM}_data.csv";
#FeaturedUsed =
EXTRACT Id string,InputFileDate DateTime
FROM #FeatureSummaryInput
USING Extractors.Csv(silent : true, skipFirstNRows : 1);
#FeaturedUsed=
SELECT *
FROM #FeaturedUsed
WHERE InputFileDate BETWEEN #ReportDate.AddDays(-3) AND #ReportDate;
If I run above code it runs with empty input. Please let me know if I am missing something. Why it is not reading correct file?
It seems like we need to must have "day" in file name pattern to work this.
Possibly I am missing something but, as you cast InputFileDate to DateTime it defaults to the first of the month, as no day is specified. For your test ReportDate set to 05/08/2017, your WHERE clause basically evaluates to Between 2017-08-02 And 2017-08-05, which will never be true.
Where do you expect the day element to come in with your files structured as yyyyMM?

Why is this DateTime.ParseExact statement not working?

The following line gives me a "String was not recognized by a valid DateTime" error:
DateTime.ParseExact("4/6/2016", "dd/MM/yyyy", Nothing)
I got this "working" example on stackoverflow, but it doesn't work for me: Parse Exact Sample and I can't figure out why.
EDIT (reedit, I mistakenly typed the last two attempts wrong):
Still no good. This is what I've found after trying all the suggestions submitted so far (thanks all). Some more info, the date string is coming from a textbox control.
Dim xxx As String = "4/6/2016" 'OR = "04/06/2016" as necessary for the sample
This does not work:
DateTime.ParseExact(xxx, "M/d/yyyy", CultureInfo.InvariantCulture)
This does not work:
DateTime.ParseExact(xxx, "MM/dd/yyyy", CultureInfo.InvariantCulture)
After, I tried something simpler with just DateTime.Parse:
DateTime.ParseExact(xxx)
I typed this out by hand. I did NOT use values from a textbox control and it DID work:
DateTime.Parse("4/6/‎2016‎")
So frustrating
Your format says you'll have two digits for the day and the month. Your actual values only have one digit.
You have two options:
Follow the format you've specified, e.g. 04/06/2016
Change the format to match the value, e.g. d/M/yyyy
Additionally - and separately - you're passing in Nothing as the format provider, which means the current culture will be used. Your format uses / which is the culture-specific date separator. If your current culture doesn't use / as its date separator, that's another problem. If you've got a fixed format, you probably want to specify CultureInfo.InvariantCulture as the format specifier instead.
Here's a short but complete program demonstrating it working:
Option Strict On
Imports System
Imports System.Globalization
Public Class Test
Shared Sub Main()
Dim xxx As String = "4/6/2016"
Dim result as DateTime = DateTime.ParseExact(xxx, "M/d/yyyy", CultureInfo.InvariantCulture)
Console.WriteLine(result)
End Sub
End Class
When you use dd or MM it expects a two digit number, so you would need to use "04/06/2016" or else replace them with their single digit versions of d and M.

Convert JavaScript DateTime to UTC with no milliseconds

Right now I'm trying to parse a date that's written in a human-readable format into a DateTime String that a SharePoint list will accept. In order to do this I've determined that I need a String in a format similar to ISO that looks like: 2007-08-20T00:00:00Z. It seems that SharePoint only accepts DateTimes that are in UTC with no milliseconds included (for whatever reason, SharePoint gives errors and won't accept the DateTime when you include the milliseconds), so I need to convert my local time into a UTC time before converting it to the ISO string.
Here's the process that the code below is using.
First I use DateJS to parse my human-date into a JavaScript Date.
(Works fine, but apparently DateJS has been abandoned, so maybe I
should change this to use MomentJS.)
Next I tried to create a new
moment in UTC. (This line is very, very wrong, and crashes my
program.)
Then I have SPServices convert it into an ISO. SPServices drops the milliseconds off the DateTime so that SharePoint will accept it. (Works
fine).
I'm sure there has to be a more elegant/working way to achieve this, instead of stitching together 3 different libraries. I'm just not sure what it is.
var jScriptStartDate = Date.parse("6/29/2014 8:30am"); //JS Date
var jScriptStartDateUTC = moment(jScriptStartDate).utc(); //local date to UTC.
var startDate = $().SPServices.SPConvertDateToISO({ //Sharepoint ISO 8601 format
dateToConvert: jScriptStartDateUTC,
dateOffset: "" //Sharepoint dates only accept UTC times, aka no dateOffset.
});
newItem.set_item('EventDate', startDate); //EventDate is internal for StartTime
You can just use moment.js, and this is all in the documentation.
moment('6/29/2014 8:30am','M/D/YYYY h:mma').toISOString()
This assumes all of the following:
The source value is in the user's time zone (that is - the time zone of the machine where the JavaScript code is running)
The input will always be in the specified format
It's also worth mentioning that if you put a space before the "am", that most modern browsers can do this natively without any library:
new Date('6/29/2014 8:30 am').toISOString()
If you take that approach, realize that the date parts are ordered according to the users locale, which might be m/d/y, or d/m/y or y/m/d.
Also, you said in the title "... with no milliseconds", but didn't elaborate on that in your question. I'm fairly certain you can pass the milliseconds without issue. There's no good reason to go out of your way to remove them. But if you must, then that would be like this with moment:
moment('6/29/2014 8:30am','M/D/YYYY h:mma').utc().format('YYYY-MM-DD[T]HH:mm:ss[Z]')
I ended up adjusting this code to use the updated DateJS (https://github.com/abritinthebay/datejs/) and a custom function I made called .toShortISOString().
The process is down to 3 lines:
var jScriptStartDate = Date.parse("6/28/2014 8:00am"); //convert to Javascript Date
var startDate = jScriptStartDate.toShortISOString(); //convert to Sharepoint ISO format (UTC with no milliseconds)
newItem.set_item('EventDate', startDate); //Strangely the internal name for Start Time is EventDate
.toShortISOString()'s main change is the removal of milliseconds, since SharePoint doesn't like milliseconds. It's code looks like this inside of the date.js file:
if ( !$P.toShortISOString ) {
$P.toShortISOString = function() {
return this.getUTCFullYear() +
"-" + p(this.getUTCMonth() + 1) +
"-" + p(this.getUTCDate()) +
"T" + p(this.getUTCHours()) +
":" + p(this.getUTCMinutes()) +
":" + p(this.getUTCSeconds()) +
//Remove the milliseconds.
//"." + String( (this.getUTCMilliseconds()/1000).toFixed(3)).slice(2, 5) +
"Z";
};
}
If you're trying to add this to date.js, make sure you have the latest version from the link above, then search the file for toISOString and place the code right below the handler for toISOString.

Parsing date by multiple formats with pivotYear set up for 2 digit years

I am having trouble to implement "simple" parsing of a date. The requirement is to allow enter year in two or four digits. When two digits are entered then make the split date for deciding into what century it belongs the first of January next year. Here is what I have so far:
DateTime now = new DateTime();
int pivotYear = now.getYear() - 49; // 2013 - 49 = 1964 where 49 is the
DateTimeParser[] parsers = {
DateTimeFormat.forPattern("dd/MM/yy").withPivotYear(pivotYear).withLocale(new Locale("en", "NZ")).getParser(),
DateTimeFormat.forPattern("dd/MM/yyyy").withLocale(new Locale("en", "NZ")).getParser()
};
DateTimeFormatter formatter = new DateTimeFormatterBuilder().append(null, parsers).toFormatter();
DateMidnight birthDate = new DateMidnight(formatter.parseDateTime(dateOfBirth));
Unfortunatelly it is not doing what I would expect. Let's say for today's date (11/04/2013) and dateOfBirth = "01/01/14" it returns 2014-01-01T00:00:00.000+13:00. The expected result would be 1914-01-01T00:00:00.000+13:00
When I look at the JavaDoc for the append method I see this sentence
The printer and parser interfaces are the low-level part of the
formatting API. Normally, instances are extracted from another
formatter. Note however that any formatter specific information, such
as the locale, time-zone, chronology, offset parsing or pivot/default
year, will not be extracted by this method.
So I have decided to move the Pivot stuff into the DateTimeFormatterBuilder class so now the code looks like this:
DateTimeParser[] parsers = {
DateTimeFormat.forPattern("dd/MM/yy").getParser(),
DateTimeFormat.forPattern("dd/MM/yyyy").getParser()
};
DateTimeFormatter formatter = new DateTimeFormatterBuilder().append(null, parsers).appendTwoDigitYear(pivotYear).toFormatter().withLocale(new Locale("en", "NZ"));
Unfortunatelly this is not sorting the issue. On contrary it is failing this time on
java.lang.IllegalArgumentException: Invalid format: "01/01/14" is too short
at org.joda.time.format.DateTimeFormatter.parseDateTime(DateTimeFormatter.java:866)
from the same javadoc I get this sentence
Appends a printer and a set of matching parsers. When parsing, the first parser in the list is selected for parsing. If it fails, the next is chosen, and so on. If none of these parsers succeeds, then the failed position of the parser that made the greatest progress is returned.
Based on this the first parser should have pick up the job but it looks like the second one is triggered and it fails because it expects longer year.
Any help would be deeply appreciated.
Cheers
Tomas
So it looks like no one is interested enough to answer so I had to figure it by myself :-).
I should be scrolling a bit down in the JavaDoc and I should have the answer in no time. There is another appendTwoDigitYear method which will do the job I am after.
So here is the code I am using right now
DateTimeFormatter formatter = new DateTimeFormatterBuilder().appendDayOfMonth(1).appendLiteral("/").appendMonthOfYear(1).appendLiteral("/").appendTwoDigitYear(pivotYear, true).toFormatter().withLocale(new Locale("en", "NZ"));
DateMidnight birthDate = new DateMidnight(formatter.parseDateTime(dateOfBirth));
Hope it will help someone in the future.
Cheers
Tomas

Resources