module Xlsxrb::Ooxml::Utils
OOXML-specific utility methods and constants.
Constants
- BUILTIN_DATE_FMT_IDS
-
Built-in numFmtIds that represent date/time formats.
- BUILTIN_NUM_FMT_CODES
-
Built-in number format codes defined by SpreadsheetML.
- DEFAULT_DATETIME_FORMAT
-
Default date-time format code used by
Writerfor Time cells. - DEFAULT_DATE_FORMAT
-
Default date format code used by
Writerfor Date cells. - EPOCH_1900
-
Excel 1900 date system epoch.
- EPOCH_1900_JD
- EPOCH_1904
-
Excel 1904 date system epoch.
- EPOCH_1904_JD
Public Class Methods
(Date date, ?date1904: bool) → untyped
Source
# File lib/xlsxrb/ooxml/utils.rb, line 65 def date_to_serial(date, date1904: false) if date1904 date.jd - EPOCH_1904_JD else serial = date.jd - EPOCH_1900_JD # Lotus 1-2-3 bug: serial 60 = Feb 29, 1900 (doesn't exist). # Dates on or after Mar 1, 1900 (raw serial >= 60) need +1. serial += 1 if serial >= 60 serial end end
Converts a Date to an Excel serial number (1900 or 1904 system).
(Time time, ?date1904: bool) → Float
Source
# File lib/xlsxrb/ooxml/utils.rb, line 91 def datetime_to_serial(time, date1904: false) date = time.to_date day_serial = date_to_serial(date, date1904: date1904) # Fractional part: seconds since midnight / seconds per day seconds_since_midnight = (time.hour * 3600) + (time.min * 60) + time.sec day_serial + (seconds_since_midnight.to_f / 86_400) end
Converts a Time to a fractional Excel serial number (1900 or 1904 system).
(untyped password, ?algorithm: untyped, ?salt: untyped, ?spin_count: untyped) → untyped
Source
# File lib/xlsxrb/ooxml/utils.rb, line 113 def hash_password(password, algorithm: "SHA-512", salt: nil, spin_count: 100_000) raise ArgumentError, "password must be a String" unless password.is_a?(String) raise ArgumentError, "spin_count must be a positive Integer" unless spin_count.is_a?(Integer) && spin_count.positive? salt_bytes = (salt || SecureRandom.random_bytes(16)).b # OOXML sheet/workbook protection hashing uses UTF-16LE password bytes. password_bytes = password.encode("UTF-16LE").b digest_name = algorithm.tr("-", "") hash = OpenSSL::Digest.digest(digest_name, salt_bytes + password_bytes) spin_count.times do |i| iteration_bytes = [i].pack("V") # little-endian uint32 hash = OpenSSL::Digest.digest(digest_name, hash + iteration_bytes) end { algorithm_name: algorithm, hash_value: [hash].pack("m0"), salt_value: [salt_bytes].pack("m0"), spin_count: spin_count } end
Hashes a plain-text password for use with sheet/workbook protection. Returns { algorithm_name:, hash_value:, salt_value:, spin_count: }. Algorithm per ECMA-376 Part 4 ยง2.4.2.24.
(Numeric serial, ?date1904: bool) → Date
Source
# File lib/xlsxrb/ooxml/utils.rb, line 79 def serial_to_date(serial, date1904: false) if date1904 EPOCH_1904 + serial else # Adjust for Lotus 1-2-3 bug. serial -= 1 if serial > 60 EPOCH_1900 + serial end end
Converts an Excel serial number (1900 or 1904 system) to a Date.
(Numeric serial, ?date1904: bool) → Time
Source
# File lib/xlsxrb/ooxml/utils.rb, line 101 def serial_to_datetime(serial, date1904: false) int_part, frac = serial.divmod(1) date = serial_to_date(int_part, date1904: date1904) total_seconds = (frac * 86_400).round hours, remaining = total_seconds.divmod(3600) minutes, seconds = remaining.divmod(60) Time.utc(date.year, date.month, date.day, hours, minutes, seconds) end
Converts a fractional Excel serial number to a Time (1900 or 1904 system, UTC).