18

I'm looking for a plain C counterpart for date.js date.parse().

That is, something that understands "week ago" or "yesterday" as input. English-only is OK.

Note: a library should not be licensed under GPL, so Git's date.c or parser for GNU date -d wouldn't do. BTW, if you wonder why wouldn't I just sit down and code this, go and look at the source of mentioned libraries...

asked Mar 19, 2012 at 20:31
5
  • For what it's worth, date.js is MIT licensed. So if the goal here is to obtain something you could link with proprietary code, you ought to be able to use date.js as a safe starting point if you have to roll your own. Although a javascript-to-C rewrite might not be a walk in the park. Commented Mar 19, 2012 at 21:39
  • 1
    That's exactly why I'm asking this question instead of just going ahead to write code :-) Commented Mar 19, 2012 at 21:57
  • If you're worried about the source complexity for writing your own parser, can you use the lex/yacc tools? Commented Mar 20, 2012 at 5:19
  • 1
    @Jerry, if you'll look at date -d sources, for example, you'll see that the most complex thing is not a parser. Commented Mar 20, 2012 at 7:16
  • and old post may help stackoverflow.com/questions/1414155/… Commented Mar 24, 2012 at 12:50

2 Answers 2

6
+50

The following solution is not exactly what you've asked for but I hope that despite not being a plain C answer it will cover your needs. Reinventing the wheel isn't a way to go so let's use date.js in C by running it with SpiderMonkey, the Mozilla JavaScript engine.

Here's how I did it. I've begun with downloading date.js and translating it into a const char* named code defined in date.js.h.

( \
 echo 'const char *code =' ; \
 curl https://datejs.googlecode.com/files/date.js | \
 sed -e 's/\\/\\\\/g; s/"/\\"/g; s/^/"/; s/\r\?$/\\n"/'; \
 echo ';' \
) > date.js.h

Then I took the JSAPI's Hello, World! as a starting point.

#include "jsapi.h"
#include "date.js.h"
static JSClass global_class = { "global", JSCLASS_GLOBAL_FLAGS,
 JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
 JSCLASS_NO_OPTIONAL_MEMBERS };
void reportError(JSContext *cx, const char *message, JSErrorReport *report) {
 fprintf(stderr, "%s:%u:%s\n",
 report->filename ? report->filename : "<no filename>",
 (unsigned int) report->lineno, message);
}
int main(int argc, const char *argv[]) {
 JSRuntime *rt;
 JSContext *cx;
 JSObject *global;
 rt = JS_NewRuntime(8L * 1024L * 1024L);
 if (rt == NULL) return 1;
 cx = JS_NewContext(rt, 8192);
 if (cx == NULL) return 1;
 JS_SetOptions(cx, JSOPTION_VAROBJFIX | JSOPTION_JIT | JSOPTION_METHODJIT);
 JS_SetVersion(cx, JSVERSION_LATEST);
 JS_SetErrorReporter(cx, reportError);
 global = JS_NewCompartmentAndGlobalObject(cx, &global_class, NULL);
 if (global == NULL) return 1;
 if (!JS_InitStandardClasses(cx, global)) return 1;
 /* Here's where the interesting stuff is starting to take place.
 * Begin by evaluating sources of date.js */
 jsval out;
 if (!JS_EvaluateScript(cx, global, code, strlen(code), "code", 1, &out))
 return 1;
 /* Now create a call to Date.parse and evaluate it. The return value should
 * be a timestamp of a given date. If no errors occur convert the timestamp
 * to a double and print it. */
 const int buflen = 1024;
 char parse[buflen + 1];
 snprintf(parse, buflen, "Date.parse(\"%s\").getTime();", argv[1]);
 if (!JS_EvaluateScript(cx, global, parse, strlen(parse), "parse", 1, &out))
 return 1;
 double val;
 JS_ValueToNumber(cx, out, &val);
 printf("%i\n", (int) (val / 1000));
 /* Finally, clean everything up. */
 JS_DestroyContext(cx);
 JS_DestroyRuntime(rt);
 JS_ShutDown();
 return 0;
}

Here's how it works in practice.

$ time ./parse "week ago"
1331938800
0.01user 0.00system 0:00.02elapsed 92%CPU (0avgtext+0avgdata 6168maxresident)k
0inputs+0outputs (0major+1651minor)pagefaults 0swaps
$ time ./parse yesterday
1332457200
0.01user 0.00system 0:00.02elapsed 84%CPU (0avgtext+0avgdata 6168maxresident)k
0inputs+0outputs (0major+1653minor)pagefaults 0swaps

As you can see it's quite fast and you could significantly increase its performance by reusing the initially created context for all subsequent calls to Date.parse.

Speaking of licensing issues, date.js is available under terms of MIT and SpiderMonkey is available under MPL 1.1, GPL 2.0 or LGPL 2.1. Linking it dynamically satisfies the non-GPL requirement.

TL;DR: git clone https://gist.github.com/2180739.git && cd 2180739 && make && ./parse yesterday

answered Mar 24, 2012 at 10:00
1
  • 3
    Hey, clever trick, thanks. I think it will even work for my case, as I do not need high performance. I'm leaving the question open in case a honest solution pops up :-) Commented Mar 24, 2012 at 16:13
-1

Date formatting is pretty gruesome, there is no easy way of doing this. You need to take into account day and month names of the selected language, then make sure you receive the data in a specific format: "dd/mm/yyyy", "day mon, yyyy" and so on. Also, as you say, you need to interpret some specific keywords, thus you need access to the current timestamp (date, time, or date&time) on the machine.

Hoping you need that for Linux, I think you can start reading from here: Convert textual time and date information back

Or you can simply tokenize your input string, by splitting it using some predefined separators (comma, slash, minus, space etc.), trimming the spaces of the tokens, and then implement an automata to handle the list of tokens and build your date variable. Make sure you add some restrictions for the input date format, and throw errors for wrong or incompatible tokens.

answered Mar 21, 2012 at 11:41
1
  • Thanks, but getdate does not understand yesterday etc. As for how to parse — I get that, but this question is about an existing solution. I'd hate to do it myself and hit all pitfalls — judging from existing GPL-ed code there are plenty. Commented Mar 24, 2012 at 7:01

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.