Date conversion .NET JSON to ISO

后端 未结 4 938
孤城傲影
孤城傲影 2020-12-03 19:32

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 Pyt

相关标签:
4条回答
  • 2020-12-03 19:34

    [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 component 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)/
    
    0 讨论(0)
  • 2020-12-03 19:41
    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;
            }
        })();
    
    0 讨论(0)
  • 2020-12-03 19:47

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

    Python >3.3 compatible. 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
    
    0 讨论(0)
  • 2020-12-03 19:54

    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.com/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'] == []
    
    0 讨论(0)
提交回复
热议问题