<commit_before>require 'date'

module IceCube
  module TimeUtil

    extend Deprecated

    DAYS = {
      :sunday => 0, :monday => 1, :tuesday => 2, :wednesday => 3,
      :thursday => 4, :friday => 5, :saturday => 6
    }

    MONTHS = {
      :january => 1, :february => 2, :march => 3, :april => 4, :may => 5,
      :june => 6, :july => 7, :august => 8, :september => 9, :october => 10,
      :november => 11, :december => 12
    }

    CLOCK_VALUES = [:year, :month, :day, :hour, :min, :sec]

    # Provides a Time.now without the usec, in the reference zone or utc offset
    def self.now(reference=Time.now)
      match_zone(Time.at(Time.now.to_i), reference)
    end

    def self.match_zone(time, reference)
      return unless time = ensure_time(time)
      if reference.respond_to? :time_zone
        time.in_time_zone(reference.time_zone)
      else
        if reference.utc?
          time.utc
        elsif reference.zone
          time.getlocal
        else
          time.getlocal(reference.utc_offset)
        end
      end
    end

    # Ensure that this is either nil, or a time
    def self.ensure_time(time, date_eod = false)
      case time
      when DateTime
        warn "IceCube: DateTime support is deprecated (please use Time) at: #{ caller[2] }"
        Time.local(time.year, time.month, time.day, time.hour, time.min, time.sec)
      when Date
        date_eod ? end_of_date(time) : time.to_time
      else
        time
      end
    end

    # Ensure that this is either nil, or a date
    def self.ensure_date(date)
      case date
      when Date then date
      else
        return Date.new(date.year, date.month, date.day)
      end
    end

    # Serialize a time appropriate for storing
    def self.serialize_time(time)
      if time.respond_to?(:time_zone)
        {:time => time.utc, :zone => time.time_zone.name}
      elsif time.is_a?(Time)
        time
      end
    end

    # Deserialize a time serialized with serialize_time
    def self.deserialize_time(time_or_hash)
      if time_or_hash.is_a?(Time)
        time_or_hash
      elsif time_or_hash.is_a?(Hash)
        hash = FlexibleHash.new(time_or_hash)
        hash[:time].in_time_zone(hash[:zone])
      end
    end

    # Check the deserialized time offset string against actual local time
    # offset to try and preserve the original offset for plain Ruby Time. If
    # the offset is the same as local we can assume the same original zone and
    # keep it.  If it was serialized with a different offset than local TZ it
    # will lose the zone and not support DST.
    def self.restore_deserialized_offset(time, orig_offset_str)
      return time if time.respond_to?(:time_zone) ||
                     time.getlocal(orig_offset_str).utc_offset == time.utc_offset
      warn "IceCube: parsed Time from nonlocal TZ. Use ActiveSupport to fix DST at: #{ caller[0] }"
      time.localtime(orig_offset_str)
    end

    # Get the beginning of a date
    def self.beginning_of_date(date, reference=nil)
      args = [date.year, date.month, date.day, 0, 0, 0]
      reference ||= Time.local(*args)
      if reference.respond_to?(:time_zone) && reference.time_zone
        reference.time_zone.local(*args)
      else
        match_zone(Time.new(*args << reference.utc_offset), reference)
      end
    end

    # Get the end of a date
    def self.end_of_date(date, reference=nil)
      args = [date.year, date.month, date.day, 23, 59, 59]<commit_msg>Enable support for ISO 8601 deserialization<commit_after>require 'date'

module IceCube
  module TimeUtil

    extend Deprecated

    DAYS = {
      :sunday => 0, :monday => 1, :tuesday => 2, :wednesday => 3,
      :thursday => 4, :friday => 5, :saturday => 6
    }

    MONTHS = {
      :january => 1, :february => 2, :march => 3, :april => 4, :may => 5,
      :june => 6, :july => 7, :august => 8, :september => 9, :october => 10,
      :november => 11, :december => 12
    }

    CLOCK_VALUES = [:year, :month, :day, :hour, :min, :sec]
    ISO8601 = /^(\d{4}\-\d\d\-\d\d([tT][\d:\.]*)?)([zZ]|([+\-])(\d\d):?(\d\d))?$/

    # Provides a Time.now without the usec, in the reference zone or utc offset
    def self.now(reference=Time.now)
      match_zone(Time.at(Time.now.to_i), reference)
    end

    def self.match_zone(time, reference)
      return unless time = ensure_time(time)
      if reference.respond_to? :time_zone
        time.in_time_zone(reference.time_zone)
      else
        if reference.utc?
          time.utc
        elsif reference.zone
          time.getlocal
        else
          time.getlocal(reference.utc_offset)
        end
      end
    end

    # Ensure that this is either nil, or a time
    def self.ensure_time(time, date_eod = false)
      case time
      when DateTime
        warn "IceCube: DateTime support is deprecated (please use Time) at: #{ caller[2] }"
        Time.local(time.year, time.month, time.day, time.hour, time.min, time.sec)
      when Date
        date_eod ? end_of_date(time) : time.to_time
      else
        time
      end
    end

    # Ensure that this is either nil, or a date
    def self.ensure_date(date)
      case date
      when Date then date
      else
        return Date.new(date.year, date.month, date.day)
      end
    end

    # Serialize a time appropriate for storing
    def self.serialize_time(time)
      if time.respond_to?(:time_zone)
        {:time => time.utc, :zone => time.time_zone.name}
      elsif time.is_a?(Time)
        time
      end
    end

    # Deserialize a time serialized with serialize_time or in ISO8601 string format
    def self.deserialize_time(time_or_hash)
      if time_or_hash.is_a?(Time)
        time_or_hash
      elsif time_or_hash.is_a?(Hash)
        hash = FlexibleHash.new(time_or_hash)
        hash[:time].in_time_zone(hash[:zone])
      elsif time_or_hash.is_a?(String) && time_or_hash =~ ISO8601
        Time.parse(time_or_hash)
      end
    end

    # Check the deserialized time offset string against actual local time
    # offset to try and preserve the original offset for plain Ruby Time. If
    # the offset is the same as local we can assume the same original zone and
    # keep it.  If it was serialized with a different offset than local TZ it
    # will lose the zone and not support DST.
    def self.restore_deserialized_offset(time, orig_offset_str)
      return time if time.respond_to?(:time_zone) ||
                     time.getlocal(orig_offset_str).utc_offset == time.utc_offset
      warn "IceCube: parsed Time from nonlocal TZ. Use ActiveSupport to fix DST at: #{ caller[0] }"
      time.localtime(orig_offset_str)
    end

    # Get the beginning of a date
    def self.beginning_of_date(date, reference=nil)
      args = [date.year, date.month, date.day, 0, 0, 0]
      reference ||= Time.local(*args)
      if reference.respond_to?(:time_zone) && reference.time_zone
        reference.time_zone.local(*args)
      else
        match_zone(Time.new(*args << reference.utc_offset), reference)
      end
    end

    # Get the end of a date
    def self.end_of_date(date, reference=nil)
      args = [date.year, date.month, date.day, 23, 59, 59]
{'fraction_non_alphanumeric': 0.10449642807115843, 'fraction_numerical': 0.01162627819022272, 'mean_word_length': 2.4710743801652892, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 45, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7556574', 'n_tokens_mistral': 2435, 'n_tokens_neox': 2328, 'n_words': 674}