go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/milo/frontend/static/common/js/time.js (about)

     1  // Copyright 2016 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // A Series of time based utilites for Milo.
    16  // Requires: moment.js, moment-timezone.js, jquery, jquery-ui
    17  
    18  // This file cannot use EcmaScript6: crbug.com/791528
    19  
    20  (function(window) {
    21    'use strict';
    22  
    23    const tz = moment.tz.guess();
    24  
    25    /**
    26     * Given a Date, return a time string in the user's local timezone.
    27     * Also return the time string in relative time from now, MTV time, and UTC
    28     * time.
    29     */
    30    function formatDate(t) {
    31      var mt = moment.tz(t, tz);
    32      if (!mt.isValid()) {
    33        return null;
    34      }
    35  
    36      return {
    37        local: mt.format("YYYY-MM-DD LT (z)"),
    38        localLong: mt.format("YYYY-MM-DD LTS (z)"),
    39        MTVLong: moment.tz(mt, "America/Los_Angeles").format(
    40          "YYYY-MM-DD LTS [(MTV)]"),
    41        UTCLong: moment.tz(mt, "UTC").format("YYYY-MM-DD LTS [(UTC)]"),
    42        fromNow: mt.fromNow(),
    43      }
    44    }
    45  
    46    /**
    47     * Given two Dates (or a Date and null, prepresenting "now"), return
    48     * a duration string, with a hover string of the start/end time in the user's
    49     * timezone and locale.
    50     */
    51    function formatDuration(start, end) {
    52      var st = moment.tz(start, tz);
    53      if (!st.isValid()) {
    54        return null;
    55      }
    56      var hover = st.format("[Started: ] YYYY-MM-DD LTS (z)");
    57      hover += "\nEnded: ";
    58      if (end == null) {
    59        hover += "N/A";
    60      } else {
    61        var et =  moment.tz(end, tz);
    62        if (!et.isValid()) {
    63          return null
    64        }
    65        hover += et.format("YYYY-MM-DD LTS (z)");
    66      }
    67      return hover;
    68    }
    69  
    70    function makeTimesLocal(locale) {
    71      // Moment.js does not set the locale automatically, it must be done by the
    72      // caller.
    73      locale = locale || window.navigator.userLanguage || window.navigator.language;
    74      moment.locale(locale);
    75  
    76      var timeSpans = document.getElementsByClassName('local-time');
    77      for (var i = 0; i < timeSpans.length; i++) {
    78        var span = timeSpans[i];
    79        try {
    80          var oldTimestamp = span.innerText;
    81          var timestamp = span.getAttribute('data-timestamp');
    82          var date = new Date(parseInt(timestamp, 10));
    83          var newTimestamp = formatDate(date);
    84          if (newTimestamp != null) {
    85            span.setAttribute(
    86              "title", [
    87                newTimestamp.fromNow,
    88                newTimestamp.localLong,
    89                newTimestamp.MTVLong,
    90                newTimestamp.UTCLong,
    91              ].join("\n")
    92            )
    93            if (!$(span).hasClass('tooltip-only'))
    94              span.innerText = newTimestamp.local;
    95          }
    96        } catch (e) {
    97          console.error('could not convert time of span', span, 'to local:', e)
    98        }
    99      }
   100    }
   101  
   102    function annotateDurations() {
   103      var durations = document.getElementsByClassName('duration');
   104      for (var i = 0; i < durations.length; i++) {
   105        var dur = durations[i];
   106        try {
   107          var start = dur.getAttribute('data-starttime');
   108          var end = dur.getAttribute('data-endtime');
   109          var hover = formatDuration(start, end);
   110          if (hover != null) {
   111            dur.setAttribute("title", hover);
   112          }
   113        } catch (e) {
   114          console.error('could not annotate duration', dur, e)
   115        }
   116      }
   117    }
   118  
   119    // Export all methods and attributes as module level functions.
   120    Object.assign(window.milo = window.milo || {}, {
   121      makeTimesLocal: makeTimesLocal,
   122      annotateDurations: annotateDurations
   123    });
   124  
   125  }(window));