Module: Xlsxrb::Ooxml::Utils
- Defined in:
- lib/xlsxrb/ooxml/utils.rb
Overview
OOXML-specific utility methods and constants.
Constant Summary collapse
- EPOCH_1900 =
Excel 1900 date system epoch.
Date.new(1899, 12, 31)
- BUILTIN_NUM_FMT_CODES =
Built-in number format codes defined by SpreadsheetML.
{ 0 => "General", 1 => "0", 2 => "0.00", 3 => "#,##0", 4 => "#,##0.00", 9 => "0%", 10 => "0.00%", 11 => "0.00E+00", 12 => "# ?/?", 13 => "# ??/??", 14 => "mm-dd-yy", 15 => "d-mmm-yy", 16 => "d-mmm", 17 => "mmm-yy", 18 => "h:mm AM/PM", 19 => "h:mm:ss AM/PM", 20 => "h:mm", 21 => "h:mm:ss", 22 => "m/d/yy h:mm", 37 => "#,##0 ;(#,##0)", 38 => "#,##0 ;[Red](#,##0)", 39 => "#,##0.00;(#,##0.00)", 40 => "#,##0.00;[Red](#,##0.00)", 45 => "mm:ss", 46 => "[h]:mm:ss", 47 => "mmss.0", 48 => "##0.0E+0", 49 => "@" }.freeze
- BUILTIN_DATE_FMT_IDS =
Built-in numFmtIds that represent date/time formats.
[14, 15, 16, 17, 18, 19, 20, 21, 22].freeze
- DEFAULT_DATE_FORMAT =
Default date format code used by Writer for Date cells.
"yyyy\\-mm\\-dd"- DEFAULT_DATETIME_FORMAT =
Default date-time format code used by Writer for Time cells.
"yyyy\\-mm\\-dd\\ hh:mm:ss"
Class Method Summary collapse
-
.date_to_serial(date) ⇒ Object
Converts a Date to an Excel serial number (1900 system).
-
.datetime_to_serial(time) ⇒ Object
Converts a Time to a fractional Excel serial number (1900 system).
-
.hash_password(password, algorithm: "SHA-512", salt: nil, spin_count: 100_000) ⇒ Object
Hashes a plain-text password for use with sheet/workbook protection.
-
.serial_to_date(serial) ⇒ Object
Converts an Excel serial number (1900 system) to a Date.
-
.serial_to_datetime(serial) ⇒ Object
Converts a fractional Excel serial number to a Time (1900 system, UTC).
Class Method Details
.date_to_serial(date) ⇒ Object
Converts a Date to an Excel serial number (1900 system).
57 58 59 60 61 62 63 |
# File 'lib/xlsxrb/ooxml/utils.rb', line 57 def date_to_serial(date) serial = (date - EPOCH_1900).to_i # 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 |
.datetime_to_serial(time) ⇒ Object
Converts a Time to a fractional Excel serial number (1900 system).
73 74 75 76 77 78 79 |
# File 'lib/xlsxrb/ooxml/utils.rb', line 73 def datetime_to_serial(time) date = time.to_date day_serial = date_to_serial(date) # 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 |
.hash_password(password, algorithm: "SHA-512", salt: nil, spin_count: 100_000) ⇒ Object
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.
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/xlsxrb/ooxml/utils.rb', line 96 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 |
.serial_to_date(serial) ⇒ Object
Converts an Excel serial number (1900 system) to a Date.
66 67 68 69 70 |
# File 'lib/xlsxrb/ooxml/utils.rb', line 66 def serial_to_date(serial) # Adjust for Lotus 1-2-3 bug. serial -= 1 if serial > 60 EPOCH_1900 + serial end |
.serial_to_datetime(serial) ⇒ Object
Converts a fractional Excel serial number to a Time (1900 system, UTC).
82 83 84 85 86 87 88 89 90 91 |
# File 'lib/xlsxrb/ooxml/utils.rb', line 82 def serial_to_datetime(serial) int_part = serial.to_i frac = serial - int_part date = serial_to_date(int_part) total_seconds = (frac * 86_400).round hours = total_seconds / 3600 minutes = (total_seconds % 3600) / 60 seconds = total_seconds % 60 Time.utc(date.year, date.month, date.day, hours, minutes, seconds) end |