fast_xlsx 0.8.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5115d5bf58c96ec3a87ab9168e954b77d2360cac3314c049efd8bed45feb634a
4
- data.tar.gz: 6ecf4642347e56626a0508acd2784cd6773f4be9ab52f3c4ede1da48031e57e1
3
+ metadata.gz: f530f027eb2e902f4bed36fdfd75af2851ff93a9762915a56f9de3e966eab593
4
+ data.tar.gz: 794ddb87412acfa82840681a9caf32f85eb0d5b47fc0921c7091f3bbde020677
5
5
  SHA512:
6
- metadata.gz: d95432cd98346cc8339c20f71c14839325e2236f43b05180960125764eb4dbff1fe434b1acf00919425b8be613e00b8fc318e548f5e4359450f9119f12cab205
7
- data.tar.gz: 2e2563be474cd5613a713f680c433a8e35186423d367004b4c02afa02905859cc139fc1efd762da66b04d748f3b1c3404def56bedb3b5c86cc0c8c3ecc4f2041
6
+ metadata.gz: 915d233e6c422187d23853c1c521bdefbf3336d85af03574882dc14a8055b1f692e3044588281c33c94e451be5123f516c4b07e2596111782c2b2a1f68fa261a
7
+ data.tar.gz: 98aa0c5de0d29816828a8fe6215c5132b7bd88297ed13bf6db9df9ddd6f0221e27f7a804a082e4430daffbb235193f1c85ffb898f41f6fee94940625d0caabb2
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.8.1] - 2026-10-03
4
+
5
+ ### Fixed
6
+
7
+ - Rails' `ActiveSupport::TimeWithZone` (e.g. `created_at`) and other objects that act like a `Time` without being one were written as text; they are dates now.
8
+
9
+ ### Changed
10
+
11
+ - Writing `Time` values is about 25% faster (read through Ruby's C API instead of method calls), and `Date` values a little faster.
12
+
3
13
  ## [0.8.0] - 2026-10-02
4
14
 
5
15
  ### Changed
data/README.md CHANGED
@@ -370,7 +370,7 @@ Values are mapped by type:
370
370
  |---|---|
371
371
  | `Integer`, `Float`, any `Numeric` | number |
372
372
  | `String` | string |
373
- | `Time`, `DateTime` | date and time (`yyyy-mm-dd hh:mm:ss` unless formatted), in its own offset |
373
+ | `Time`, `DateTime`, time-like objects such as Rails' `ActiveSupport::TimeWithZone` | date and time (`yyyy-mm-dd hh:mm:ss` unless formatted), in its own offset |
374
374
  | `Date` | date (`yyyy-mm-dd` unless formatted) |
375
375
  | `FastXlsx::Formula.new("SUM(A1:A9)")` | formula |
376
376
  | `FastXlsx::URL.new("https://…")`, `URL.new(url, text: "Title")` | hyperlink (optionally showing other text) |
data/bench/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- fast_xlsx (0.8.0)
4
+ fast_xlsx (0.8.1)
5
5
  rb_sys (~> 0.9.130)
6
6
 
7
7
  GEM
@@ -77,7 +77,7 @@ DEPENDENCIES
77
77
  CHECKSUMS
78
78
  caxlsx (4.5.0) sha256=e3d98d859f148df05d5462086b5079b523f29c1766b569535f1d68629ce743ff
79
79
  fast_excel (0.5.0) sha256=59c418bdcf586a6030798d4e3a9f575742badaceaf7bb90f38eee5feb5bdc478
80
- fast_xlsx (0.8.0)
80
+ fast_xlsx (0.8.1)
81
81
  ffi (1.17.4-aarch64-linux-gnu) sha256=b208f06f91ffd8f5e1193da3cae3d2ccfc27fc36fba577baf698d26d91c080df
82
82
  ffi (1.17.4-aarch64-linux-musl) sha256=9286b7a615f2676245283aef0a0a3b475ae3aae2bb5448baace630bb77b91f39
83
83
  ffi (1.17.4-arm-linux-gnu) sha256=d6dbddf7cb77bf955411af5f187a65b8cd378cb003c15c05697f5feee1cb1564
@@ -10,7 +10,7 @@ publish = false
10
10
  crate-type = ["cdylib"]
11
11
 
12
12
  [dependencies]
13
- magnus = "0.9"
13
+ magnus = { version = "0.9", features = ["rb-sys"] }
14
14
  rb-sys = { version = "0.9", features = ["stable-api-compiled-fallback"] }
15
15
  # No "zlib" feature: without it zip compresses with zlib-rs, which saves
16
16
  # 20-30% faster than the system zlib (and needs no C library).
@@ -328,7 +328,29 @@ fn excel_serial(days: f64) -> Result<f64, Error> {
328
328
  }
329
329
 
330
330
  // Time: seconds since 1970-01-01 (serial day 25569), in its own offset.
331
+ // For a Time (checked by the caller): Ruby's C functions, with no method calls,
332
+ // since this runs once per cell.
331
333
  fn excel_time(v: Value) -> Result<f64, Error> {
334
+ use magnus::rb_sys::{protect, AsRawValue, FromRawValue};
335
+ // Both can raise (a Time out of range or uninitialized, or a zone object
336
+ // whose Ruby code fails), so they run under protect: a raise becomes an
337
+ // Err instead of a longjmp over these Rust frames.
338
+ let mut spec = None;
339
+ protect(|| {
340
+ // SAFETY: protect catches anything this raises.
341
+ spec = Some(unsafe { rb_sys::rb_time_timespec(v.as_raw()) });
342
+ rb_sys::Qnil as rb_sys::VALUE
343
+ })?;
344
+ // SAFETY: as above.
345
+ let offset = protect(|| unsafe { rb_sys::rb_time_utc_offset(v.as_raw()) })?;
346
+ let (spec, offset) = (spec.unwrap(), unsafe { Value::from_raw(offset) });
347
+ let secs = spec.tv_sec as f64 + spec.tv_nsec as f64 / 1e9;
348
+ excel_serial((secs + i64::try_convert(offset)? as f64) / 86400.0 + 25569.0)
349
+ }
350
+
351
+ // Something that acts like a Time without being one at the C level, such as
352
+ // Rails' ActiveSupport::TimeWithZone (it delegates to a Time).
353
+ fn excel_time_like(v: Value) -> Result<f64, Error> {
332
354
  let secs: f64 = v.funcall("to_f", ())?;
333
355
  let offset: i64 = v.funcall("utc_offset", ())?;
334
356
  excel_serial((secs + offset as f64) / 86400.0 + 25569.0)
@@ -336,9 +358,14 @@ fn excel_time(v: Value) -> Result<f64, Error> {
336
358
 
337
359
  // Date / DateTime: Julian day and day fraction are both in the object's own
338
360
  // offset. JD 2415019 is 1899-12-30.
339
- fn excel_date(v: Value) -> Result<f64, Error> {
361
+ // `time`: a DateTime, with a time of day; a Date's day fraction is always 0.
362
+ fn excel_date(v: Value, time: bool) -> Result<f64, Error> {
340
363
  let jd: i64 = v.funcall("jd", ())?;
341
- let fraction: f64 = f64::try_convert(v.funcall("day_fraction", ())?)?;
364
+ let fraction = if time {
365
+ f64::try_convert(v.funcall("day_fraction", ())?)?
366
+ } else {
367
+ 0.0
368
+ };
342
369
  excel_serial((jd - 2_415_019) as f64 + fraction)
343
370
  }
344
371
 
@@ -413,7 +440,10 @@ impl CellValue {
413
440
  CellValue::Rich(parts)
414
441
  } else if v.respond_to("jd", false)? {
415
442
  // Date has no #hour; DateTime does.
416
- CellValue::Date(excel_date(v)?, v.respond_to("hour", false)?)
443
+ let time = v.respond_to("hour", false)?;
444
+ CellValue::Date(excel_date(v, time)?, time)
445
+ } else if v.respond_to("utc_offset", false)? && v.respond_to("to_f", false)? {
446
+ CellValue::Date(excel_time_like(v)?, true)
417
447
  } else {
418
448
  CellValue::Text(v.funcall("to_s", ())?)
419
449
  };
@@ -2,5 +2,5 @@
2
2
 
3
3
  module FastXlsx
4
4
  # The gem version.
5
- VERSION = "0.8.0"
5
+ VERSION = "0.8.1"
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fast_xlsx
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zac