Moment: Berechnung des Mindestalters mit Grenzgeburtstagswerten führt zu unerwartetem Verhalten

Erstellt am 27. Feb. 2017  ·  3Kommentare  ·  Quelle: moment/moment

Beschreibung des Problems und Schritte zur Reproduktion

Ich möchte überprüfen, ob eine Person genau oder über 18 Jahre alt ist. Also habe ich die Funktionen diff() und duration() verwendet, um das Alter einer Person zu berechnen. Ich habe einige Tests mit Grenzwerten geschrieben, um meine Logik zu testen. Ich wollte testen, ob ich genau einen Tag jünger als 18 und genau 18 Jahre alt bin. Also habe ich mir zwei Geburtstage zum Testen ausgesucht (heute ist der 27.02.2017):

  • genau 18: 27.02.1999
  • ein Tag unter 18: 28.02.1999

Reproduzieren

// today date is: 27.02.2017

// exactly age 18    
var birthday = moment("27.02.1999", "DD.MM.YYYY"),
    age = moment.duration(moment().diff(birthday)).asYears();

      console.log(age); // output: 18.00325100985672; expected: == 18

// one day under age 18
var birthday = moment("28.02.1999", "DD.MM.YYYY"),
    age = moment.duration(moment().diff(birthday)).asYears();

    console.log(age); // output: 18.00053005036735; expected: < 18

Ich denke, die Rechnung ist richtig, wegen der Schaltjahre. Aber in Bezug auf den Geburtstag sollte die Person nicht 18 Jahre alt sein. Vielleicht gibt es eine andere Möglichkeit, es mit momentjs zu tun, und ich mache es falsch. Wenn ja, wäre es schön, in der Dokumentation von momentjs erwähnt zu werden.

Produktionscode

<form id="newsletter-form" data-parsley-validate="">
  <input id="birthday" type="text" class="form-control" required="" data-parsley-minage="18">
  <input type="submit" class="btn btn-default" value="subscribe">
</form>

<script type="text/javascript">
    $(function () {
        window.Parsley.addValidator('minage', {
            validateString: function(value, minAge) {
                var birthday = moment(value, "DD.MM.YYYY"),
                    age = moment.duration(moment().diff(birthday)).asYears();

                return (age >= minAge);
            },
            requirementType: 'integer',
            messages: {
                en: 'You must be mature.'
            }
        });
    });
</script>
<script type="text/javascript">
    $(function () {
        $('#newsletter-form').parsley()
            // field validation
            .on('form:submit', function() {
                return false; // do not submit
            });
    });
</script>

Umfeld

Chrome-Version 56.0.2924.87 (64-Bit) unter Windows 7

Weitere Informationen, die hilfreich sein könnten

  • Zeitzone der Maschine: "(UTC+01:00) Amsterdam, Berlin, Bern, Rom, Stockholm, Wien"
  • Uhrzeit und Datum der Codeausführung: "Mon Feb 27 2017 13:38:04 GMT+0100"
  • Andere verwendete Bibliotheken: jquery-3.1.1, bootstrap-3.3.7, bootstrap-datepicker-1.6.4, parselyjs-2.6.2
console.log( (new Date()).toString()) // Mon Feb 27 2017 13:38:04 GMT+0100 (Mitteleuropäische Zeit)
console.log((new Date()).toLocaleString()) // 27.2.2017, 13:38:04
console.log( (new Date()).getTimezoneOffset()) // -60
console.log( navigator.userAgent) // Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36
console.log(moment.version) // 2.17.1

Hilfreichster Kommentar

Funktioniert es besser, wenn Sie nur verwenden?

age = moment().diff(birthday, 'years');

Alle 3 Kommentare

Ich denke , die Berechnung ist falsch, aber es ist ganz nah. Vielleicht wegen Rundungsfehlern?

Zum Beispiel:

a = moment("27.02.1999", "DD.MM.YYYY");
b = moment("28.02.1999", "DD.MM.YYYY");
c = moment("27.02.2017", "DD.MM.YYYY");
moment.duration(c.diff(a)).asYears(); // 18.00173857094944
moment.duration(c.diff(b)).asYears(); // 17.99900066394245

In diesem Fall gibt moment.duration(end.diff(start)).asYears() 18 ungefähr 16 Stunden vor dem eigentlichen Zeitpunkt zurück.

Wenn Sie versuchen zu überprüfen, ob ein Alter über oder gleich 18 ist, können Sie die Jahre vergleichen, dann (bei einem Abstand von 18 Jahren) die Monate und dann die Tage.

// pseudocode, correctness not guaranteed
function is18(start, end) {
  if (end.year() - start.year() == 18) {
    if (end.month() == start.month()) {
      return end.date() >= start.date();
    }
    return end.month() > start.month();
  }
  return end.year() - 18 > start.year();
}

Funktioniert es besser, wenn Sie nur verwenden?

age = moment().diff(birthday, 'years');

@mj1856

Ja, das funktioniert ganz gut.

// today date is: 03.03.2017

// exactly age 18    
var birthday = moment("03.03.1999", "DD.MM.YYYY"),
    age = moment().diff(birthday, 'years');

      console.log(age); // output: 18; expected: == 18

// one day under age 18
var birthday = moment("04.03.1999", "DD.MM.YYYY"),
    age = moment().diff(birthday, 'years');

    console.log(age); // output: 17; expected: < 18
War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

slavafomin picture slavafomin  ·  3Kommentare

tanepiper picture tanepiper  ·  3Kommentare

alvarotrigo picture alvarotrigo  ·  3Kommentare

paulyoung picture paulyoung  ·  3Kommentare

RobinvanderVliet picture RobinvanderVliet  ·  3Kommentare