admin管理员组

文章数量:1302272

How can I convert a date time format from JSON.Net such as:

/Date(1154970000000+0700)/

To ISO-?? format 2011-12-18T23:34:59Z

Preferably in either Python or Javascript.

Ive decided on the latter as its seems in the JS world the most widely used, humanly readable and naturally sortable. I'll store offsets on a per user basis.

If an implementation is again a bit much too ask, if someone can tell me the correct name for both formats I might have more luck in understanding how to convert.

How can I convert a date time format from JSON.Net such as:

/Date(1154970000000+0700)/

To ISO-?? format 2011-12-18T23:34:59Z

Preferably in either Python or Javascript.

Ive decided on the latter as its seems in the JS world the most widely used, humanly readable and naturally sortable. I'll store offsets on a per user basis.

If an implementation is again a bit much too ask, if someone can tell me the correct name for both formats I might have more luck in understanding how to convert.

Share edited Aug 3, 2017 at 22:56 RobG 148k32 gold badges179 silver badges214 bronze badges asked Apr 26, 2011 at 5:46 user53791user53791
Add a ment  | 

4 Answers 4

Reset to default 3

[Replacement answer]

Here is a Python 2.x version. Only the print statements in the testing section need to be changed for Python 3.x.

As far as I can ascertain by googling: The main ponent is milliseconds since 1970-01-01. It can be negative. A + sign is NOT expected for positive numbers. This can be followed by an OPTIONAL offset from UTC, which consists of 5 characters: an mandatory sign (+ or -), 2 digits for hours, and 2 digits for minutes. All of the above is preceded by "/Date(" and followed by ")/".

This answer provides a function to convert the JSON.NET string to a Python datetime.datetime (timestamp) object, and 2 functions to return ISO format truncated to seconds and milliseconds respectively.

Script:

# /Date(1154970000000+0700)/
# 0123456............7654321
# without timezone:
# /Date(1154970000000)/
# 0123456............21
# dodgy case
# /Date(-1234)/
# 3210987654321
import datetime

def json_date_as_datetime(jd):
    sign = jd[-7]
    if sign not in '-+' or len(jd) == 13:
        millisecs = int(jd[6:-2])
    else:
        millisecs = int(jd[6:-7])
        hh = int(jd[-7:-4])
        mm = int(jd[-4:-2])
        if sign == '-': mm = -mm
        millisecs += (hh * 60 + mm) * 60000
    return datetime.datetime(1970, 1, 1) \
        + datetime.timedelta(microseconds=millisecs * 1000)

def datetime_as_iso(dt):
    return dt.strftime("%Y-%m-%dT%H:%M:%SZ") # truncates

def datetime_as_iso_ms(dt): # with millisecs as fraction
    return dt.strftime("%Y-%m-%dT%H:%M:%S.%%03dZ") \
        % (dt.microsecond // 1000) # truncate    

if __name__ == "__main__":

    tests = """\
    /Date(1154970000000+0700)/
    /Date(-1234)/
    /Date(1000+0200)/
    /Date(0+0000)/
    /Date(0)/
    /Date(0-0700)/
    /Date(0-0730)/
    /Date(0-0030)/
    /Date(-1577923200000+0000)/
    /Date(1)/
    /Date(499)/
    /Date(500)/
    /Date(501)/
    /Date(999)/
    /Date(1000)/
    /Date(-1)/
    """.splitlines()

    for test in tests:
        test = test.strip()
        if not test: continue
        d = json_date_as_datetime(test)
        print datetime_as_iso_ms(d), test

Output:

2006-08-08T00:00:00.000Z /Date(1154970000000+0700)/
1969-12-31T23:59:58.766Z /Date(-1234)/
1970-01-01T02:00:01.000Z /Date(1000+0200)/
1970-01-01T00:00:00.000Z /Date(0+0000)/
1970-01-01T00:00:00.000Z /Date(0)/
1969-12-31T17:00:00.000Z /Date(0-0700)/
1969-12-31T16:30:00.000Z /Date(0-0730)/
1969-12-31T23:30:00.000Z /Date(0-0030)/
1920-01-01T00:00:00.000Z /Date(-1577923200000+0000)/
1970-01-01T00:00:00.001Z /Date(1)/
1970-01-01T00:00:00.499Z /Date(499)/
1970-01-01T00:00:00.500Z /Date(500)/
1970-01-01T00:00:00.501Z /Date(501)/
1970-01-01T00:00:00.999Z /Date(999)/
1970-01-01T00:00:01.000Z /Date(1000)/
1969-12-31T23:59:59.999Z /Date(-1)/
jsonDate = "/Date(1154970000000+0700)/";

var strDate = parseInt(jsonDate.replace(/\/Date\(([-\d]+).*$/, "$1"));
var strHour = parseInt(jsonDate.replace(/.*\d([+-]\d\d).*$/, "$1"), 10);
var strMin = parseInt(jsonDate.replace(/.*\d([+-])\d\d(\d\d).*$/, "$1$2"), 10);

var date = new Date(strDate);
if (!isNaN(strHour)) date.setHours(date.getHours() + strHour);
if (!isNaN(strMin)) date.setMinutes(date.getMinutes() + strMin);

var out = date.toISOString();

And the function to convert to ISO:

var toISOString = Date.prototype.toISOString ?
    function(d){return d}:
    (function(){
        function t(i){return i<10?"0"+i:i};
        function h(i){return i.length<2?"00"+i:i.length<3?"0"+i:3<i.length?Math.round(i/Math.pow(10,i.length-3)):i};
        function toISOString(){
            return "".concat(
                this.getUTCFullYear(), "-",
                t(this.getUTCMonth() + 1), "-",
                t(this.getUTCDate()), "T",
                t(this.getUTCHours()), ":",
                t(this.getUTCMinutes()), ":",
                t(this.getUTCSeconds()), ".",
                h("" + this.getUTCMilliseconds()), "Z"
            );
        };
        return function(d){
            d.toISOString = toISOString;
            return d;
        }
    })();

Returns timezone aware datetimes and provides correct output for John Machin's test cases and "/Date(1428145200000+1200)/"

Python >3.3 patible. For 2.7, use pytz.utc instead of datetime.timezone.utc.

from datetime import datetime, timedelta, timezone
import re


def jsondate(jsondate, tzinfo=timezone.utc):
    """Converts an ASP.NET json date: "/DATE(x)/" to tz-aware datetime object."""

    regex = (
        r"/Date\("
        r"(?P<milleseconds>[\-]?\d+)"
        r"(?P<offset>"
        r"(?P<offset_sign>[\+\-])"
        r"(?P<offset_hours>[01][0-9]|2[0-3])"
        r"(?P<offset_mins>[0-5][0-9])"
        r")?\)/"
    )
    try:
        parts = re.match(regex, jsondate).groupdict()
    except (AttributeError, TypeError):
        raise ValueError("Unsupported ASP.NET JSON Date Format: %s" % jsondate)

    since_epoch = timedelta(microseconds=1000 * int(parts['milleseconds']))
    if parts.get('offset'):
        since_epoch += timedelta(
            hours=int("%s%s" % (parts['offset_sign'], parts['offset_hours'])),
            minutes=int("%s%s" % (parts['offset_sign'], parts['offset_mins']))
        )
    return datetime(year=1970, month=1, day=1, tzinfo=tzinfo) + since_epoch

Here's a little class I wrote years ago to clean up this sort of invalid JSON that some .NET library generates:

class DotNETDecoder(simplejson.JSONDecoder):
    '''
    This is a decoder to convert .NET encoded JSON into python objects
    The motivation for this is the way .NET encodes dates.
    See:
    https://msdn.microsoft./en-us/library/bb299886.aspx#intro_to_json_topic2
    .NET encodes datetimes like this: "\/Date(628318530718)\/"
    '''

    def __init__(self, timezone, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        self.parse_string = self._date_parse_string(timezone)
        self.scan_once = py_make_scanner(self)

    @staticmethod
    def _date_parse_string(timezone):
        def _parse_string(string, idx, encoding, strict):
            obj = scanstring(string, idx, encoding, strict)
            if isinstance(obj[0], str):
                match = date_match.search(obj[0])
                if match:
                    return [dt.datetime.fromtimestamp(
                                int(match.group(1)) / 1000, timezone),
                            obj[1]]
            return obj
        return _parse_string

And a test case / example:

def test_can_decode_dotnet_json_dates():                                                                                                                                                                     
    jsonstr = '{"date": "Date(1330848000000)", "f": "b", "l": [], "i": 5}'                                                                                                                                   
    timezone = pytz.timezone('America/New_York')                                                                                                                                                             
    obj = json.loads(jsonstr, cls=DotNETDecoder, timezone=timezone)                                                                                                                                          
    assert obj['date'] == timezone.localize(dt.datetime(2012, 3, 4, 3, 0))                                                                                                                                   
    assert obj['f'] == "b"                                                                                                                                                                                   
    assert obj['i'] == 5                                                                                                                                                                                     
    assert obj['l'] == []

本文标签: javascriptDate conversion NET JSON to ISOStack Overflow