diff options
| author | Thomas Fitzsimmons | 2020-09-29 17:15:40 -0400 |
|---|---|---|
| committer | Thomas Fitzsimmons | 2020-09-29 20:01:29 -0400 |
| commit | e7670a3ce02dfb4bfe7e94aa02f7171ec0598ef5 (patch) | |
| tree | 436e1d93c7565af2b52071c877c6bc07cf4fc700 | |
| parent | 7e45ed3a9674e9f436c337bed647ce9f60939ee0 (diff) | |
| download | emacs-e7670a3ce02dfb4bfe7e94aa02f7171ec0598ef5.tar.gz emacs-e7670a3ce02dfb4bfe7e94aa02f7171ec0598ef5.zip | |
soap-client: Update soap-decode-date-time
* lisp/net/soap-client.el (soap-decode-date-time): Add support for
Emacs versions that support fractional seconds. Make DATATYPE
optional. Remove FIXME comment.
Co-authored-by: Paul Eggert <eggert@cs.ucla.edu>
| -rw-r--r-- | lisp/net/soap-client.el | 143 |
1 files changed, 110 insertions, 33 deletions
diff --git a/lisp/net/soap-client.el b/lisp/net/soap-client.el index 81bbc336dc3..8b5ac613b3b 100644 --- a/lisp/net/soap-client.el +++ b/lisp/net/soap-client.el | |||
| @@ -551,30 +551,77 @@ This is a specialization of `soap-encode-value' for | |||
| 551 | (soap-validate-xs-basic-type value-string type) | 551 | (soap-validate-xs-basic-type value-string type) |
| 552 | (insert value-string))))) | 552 | (insert value-string))))) |
| 553 | 553 | ||
| 554 | ;; Inspired by rng-xsd-convert-date-time. | 554 | (defun soap-decode-date-time (date-time-string &optional datatype) |
| 555 | (defun soap-decode-date-time (date-time-string datatype) | ||
| 556 | "Decode DATE-TIME-STRING as DATATYPE. | 555 | "Decode DATE-TIME-STRING as DATATYPE. |
| 557 | DATE-TIME-STRING should be in ISO 8601 basic or extended format. | 556 | DATE-TIME-STRING should be in ISO 8601 basic or extended format. |
| 558 | DATATYPE is one of dateTime, time, date, gYearMonth, gYear, | 557 | DATATYPE can be omitted, or one of the symbols dateTime, time, |
| 559 | gMonthDay, gDay or gMonth. | 558 | date, gYearMonth, gYear, gMonthDay, gDay, or gMonth. If Emacs is |
| 560 | 559 | a version that supports fractional seconds, DATATYPE can also be | |
| 561 | Return a list in a format (SEC MINUTE HOUR DAY MONTH YEAR | 560 | dateTime-subsecond, or time-subsecond. On older versions of |
| 562 | SEC-FRACTION DATATYPE ZONE). This format is meant to be similar | 561 | Emacs (prior to 27.1), which do not support fractional seconds, |
| 563 | to that returned by `decode-time' (and compatible with | 562 | leaving DATATYPE nil means that subseconds in DATE-TIME-STRING |
| 564 | `encode-time'). The differences are the SEC (seconds) | 563 | will be ignored. |
| 565 | field is always an integer, the DOW (day-of-week) field | 564 | |
| 566 | is replaced with SEC-FRACTION, a float representing the | 565 | Return a list in a format identical or similar to that returned |
| 567 | fractional seconds, and the DST (daylight savings time) field is | 566 | by `decode-time'. The returned format is always compatible with |
| 568 | replaced with DATATYPE, a symbol representing the XSD primitive | 567 | `encode-time'. If DATATYPE is omitted or nil, this function will |
| 569 | datatype. This symbol can be used to determine which fields | 568 | return a list that has exactly the same format as that returned |
| 570 | apply and which don't when it's not already clear from context. | 569 | by `decode-time'. |
| 571 | For example a datatype of `time' means the year, month and day | 570 | |
| 571 | Note that on versions of Emacs that predate support for | ||
| 572 | fractional seconds, `encode-time' will not notice the SUBSECOND | ||
| 573 | field so it must be handled specially. | ||
| 574 | |||
| 575 | The formats returned by this function are as follows, where _ | ||
| 576 | means \"should be ignored\": | ||
| 577 | |||
| 578 | DATATYPE | Return format | ||
| 579 | ------------+---------------------------------------------------------------- | ||
| 580 | nil | (SECOND MINUTE HOUR DAY MONTH YEAR DOW DST UTCOFF) | ||
| 581 | dateTime | (SECOND MINUTE HOUR DAY MONTH YEAR SUBSECOND dateTime UTCOFF) | ||
| 582 | time | (SECOND MINUTE HOUR _ _ _ SUBSECOND time _) | ||
| 583 | date | (_ _ _ DAY MONTH YEAR _ date _) | ||
| 584 | gYearMonth | (_ _ _ _ MONTH YEAR _ gYearMonth _) | ||
| 585 | gYear | (_ _ _ _ _ YEAR _ gYear _) | ||
| 586 | gMonthDay | (_ _ _ DAY MONTH _ _ gMonthDay _) | ||
| 587 | gDay | (_ _ _ DAY _ _ _ gDay _) | ||
| 588 | gMonth | (_ _ _ _ MONTH _ _ gMonth _) | ||
| 589 | |||
| 590 | When DATATYPE is dateTime or time, the DOW (day-of-week) field is | ||
| 591 | replaced with SUBSECOND, a float representing the fractional | ||
| 592 | seconds, and the DST (daylight savings time) field is replaced | ||
| 593 | with DATATYPE, a symbol representing the XSD primitive datatype. | ||
| 594 | This symbol can be used to determine which fields apply and which | ||
| 595 | do not, when it is not already clear from context. For example a | ||
| 596 | datatype of `time' means the year, month, day and time zone | ||
| 572 | fields should be ignored. | 597 | fields should be ignored. |
| 573 | 598 | ||
| 574 | This function will throw an error if DATE-TIME-STRING represents | 599 | New code that depends on Emacs 27.1 or newer anyway, and that |
| 575 | a leap second, since the XML Schema 1.1 standard explicitly | 600 | wants dateTime or time but with the first argument with subsecond |
| 576 | disallows them." | 601 | resolution, i.e., (TICKS . HZ), can set DATATYPE to |
| 577 | (let* ((datetime-regexp (cadr (get datatype 'rng-xsd-convert))) | 602 | dateTime-subsecond or time-subsecond respectively. This function |
| 603 | throws an error if dateTime-subsecond or time-subsecond is | ||
| 604 | specified when Emacs does not support subsecond resolution. | ||
| 605 | |||
| 606 | This function throws an error if DATE-TIME-STRING represents a | ||
| 607 | leap second, since the XML Schema 1.1 standard does not support | ||
| 608 | representing leap seconds." | ||
| 609 | (let* ((new-decode-time (condition-case nil | ||
| 610 | (not (null | ||
| 611 | (with-no-warnings (decode-time nil nil t)))) | ||
| 612 | (wrong-number-of-arguments))) | ||
| 613 | (new-decode-time-second nil) | ||
| 614 | (no-support "This Emacs version does not support %s") | ||
| 615 | (datetime-regexp-type | ||
| 616 | (cl-case datatype | ||
| 617 | ((dateTime-subsecond time-subsecond) | ||
| 618 | (if new-decode-time | ||
| 619 | (intern (replace-regexp-in-string | ||
| 620 | "-subsecond" "" (symbol-name datatype))) | ||
| 621 | (error (format no-support (symbol-name datatype))))) | ||
| 622 | ((nil) 'dateTime) | ||
| 623 | (otherwise datatype))) | ||
| 624 | (datetime-regexp (cadr (get datetime-regexp-type 'rng-xsd-convert))) | ||
| 578 | (year-sign (progn | 625 | (year-sign (progn |
| 579 | (string-match datetime-regexp date-time-string) | 626 | (string-match datetime-regexp date-time-string) |
| 580 | (match-string 1 date-time-string))) | 627 | (match-string 1 date-time-string))) |
| @@ -585,6 +632,7 @@ disallows them." | |||
| 585 | (minute (match-string 6 date-time-string)) | 632 | (minute (match-string 6 date-time-string)) |
| 586 | (second (match-string 7 date-time-string)) | 633 | (second (match-string 7 date-time-string)) |
| 587 | (second-fraction (match-string 8 date-time-string)) | 634 | (second-fraction (match-string 8 date-time-string)) |
| 635 | (time-zone nil) | ||
| 588 | (has-time-zone (match-string 9 date-time-string)) | 636 | (has-time-zone (match-string 9 date-time-string)) |
| 589 | (time-zone-sign (match-string 10 date-time-string)) | 637 | (time-zone-sign (match-string 10 date-time-string)) |
| 590 | (time-zone-hour (match-string 11 date-time-string)) | 638 | (time-zone-hour (match-string 11 date-time-string)) |
| @@ -605,11 +653,28 @@ disallows them." | |||
| 605 | (if hour (string-to-number hour) 0)) | 653 | (if hour (string-to-number hour) 0)) |
| 606 | (setq minute | 654 | (setq minute |
| 607 | (if minute (string-to-number minute) 0)) | 655 | (if minute (string-to-number minute) 0)) |
| 656 | (when new-decode-time | ||
| 657 | (setq new-decode-time-second | ||
| 658 | (if second | ||
| 659 | (if second-fraction | ||
| 660 | (let* ((second-fraction-significand | ||
| 661 | (replace-regexp-in-string "\\." "" second-fraction)) | ||
| 662 | (hertz | ||
| 663 | (expt 10 (length second-fraction-significand))) | ||
| 664 | (ticks (+ (* hertz (string-to-number second)) | ||
| 665 | (string-to-number | ||
| 666 | second-fraction-significand)))) | ||
| 667 | (cons ticks hertz)) | ||
| 668 | (cons second 1))))) | ||
| 608 | (setq second | 669 | (setq second |
| 609 | (if second (string-to-number second) 0)) | 670 | (if second (string-to-number second) 0)) |
| 610 | (setq second-fraction | 671 | (setq second-fraction |
| 611 | (if second-fraction | 672 | (if second-fraction |
| 612 | (float (string-to-number second-fraction)) | 673 | (progn |
| 674 | (when (and (not datatype) (not new-decode-time)) | ||
| 675 | (message | ||
| 676 | "soap-decode-date-time: Discarding fractional seconds")) | ||
| 677 | (float (string-to-number second-fraction))) | ||
| 613 | 0.0)) | 678 | 0.0)) |
| 614 | (setq has-time-zone (and has-time-zone t)) | 679 | (setq has-time-zone (and has-time-zone t)) |
| 615 | (setq time-zone-sign | 680 | (setq time-zone-sign |
| @@ -618,6 +683,14 @@ disallows them." | |||
| 618 | (if time-zone-hour (string-to-number time-zone-hour) 0)) | 683 | (if time-zone-hour (string-to-number time-zone-hour) 0)) |
| 619 | (setq time-zone-minute | 684 | (setq time-zone-minute |
| 620 | (if time-zone-minute (string-to-number time-zone-minute) 0)) | 685 | (if time-zone-minute (string-to-number time-zone-minute) 0)) |
| 686 | (setq time-zone (if has-time-zone | ||
| 687 | (* (rng-xsd-time-to-seconds | ||
| 688 | time-zone-hour | ||
| 689 | time-zone-minute | ||
| 690 | 0) | ||
| 691 | time-zone-sign) | ||
| 692 | ;; UTC. | ||
| 693 | 0)) | ||
| 621 | (unless (and | 694 | (unless (and |
| 622 | ;; XSD does not allow year 0. | 695 | ;; XSD does not allow year 0. |
| 623 | (> year 0) | 696 | (> year 0) |
| @@ -635,18 +708,22 @@ disallows them." | |||
| 635 | (>= time-zone-minute 0) | 708 | (>= time-zone-minute 0) |
| 636 | (<= time-zone-minute 59)) | 709 | (<= time-zone-minute 59)) |
| 637 | (error "Invalid or unsupported time: %s" date-time-string)) | 710 | (error "Invalid or unsupported time: %s" date-time-string)) |
| 638 | ;; Return a value in a format similar to that returned by decode-time, and | 711 | ;; Return a value in a format identical or similar to that |
| 639 | ;; suitable for (apply #'encode-time ...). | 712 | ;; returned by decode-time, and always suitable for (apply |
| 640 | ;; FIXME: Nobody uses this idiosyncratic value. Perhaps stop returning it? | 713 | ;; #'encode-time ...). |
| 641 | (list second minute hour day month year second-fraction datatype | 714 | (if datatype |
| 642 | (if has-time-zone | 715 | (list (if (memq datatype '(dateTime-subsecond time-subsecond)) |
| 643 | (* (rng-xsd-time-to-seconds | 716 | new-decode-time-second |
| 644 | time-zone-hour | 717 | second) |
| 645 | time-zone-minute | 718 | minute hour day month year second-fraction datatype time-zone) |
| 646 | 0) | 719 | (let ((time |
| 647 | time-zone-sign) | 720 | (apply |
| 648 | ;; UTC. | 721 | #'encode-time (list |
| 649 | 0)))) | 722 | (if new-decode-time new-decode-time-second second) |
| 723 | minute hour day month year nil nil time-zone)))) | ||
| 724 | (if new-decode-time | ||
| 725 | (with-no-warnings (decode-time time nil t)) | ||
| 726 | (decode-time time)))))) | ||
| 650 | 727 | ||
| 651 | (defun soap-decode-xs-basic-type (type node) | 728 | (defun soap-decode-xs-basic-type (type node) |
| 652 | "Use TYPE, a `soap-xs-basic-type', to decode the contents of NODE. | 729 | "Use TYPE, a `soap-xs-basic-type', to decode the contents of NODE. |