Skip to content

Commit

Permalink
add option to lookup multiple coordinates from stdin (#166)
Browse files Browse the repository at this point in the history
  • Loading branch information
DvdGiessen authored Feb 21, 2025
1 parent 3f4de05 commit 337a333
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 6 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,18 @@ Rust port's Python binding; you can view it
- Python, see [`ringsaturn/tzfpy`](https://github.com/ringsaturn/tzfpy)
- Wasm, see [`ringsaturn/tzf-wasm`](https://github.com/ringsaturn/tzf-wasm)

## Command line

The binary helps in debugging tzf-rs and using it in (scripting) languages
without bindings. Either specify the coordinates as parameters to get a single
time zone, or to look up multiple coordinates efficiently specify the ordering
and pipe them to the binary one pair of coordinates per line.

```shell
tzf --lng 116.3883 --lat 39.9289
echo -e "116.3883 39.9289\n116.3883, 39.9289" | tzf --stdin-order lng-lat
```

## LICENSE

This project is licensed under the [MIT license](./LICENSE). The data is
Expand Down
58 changes: 52 additions & 6 deletions src/bin/tzf.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,69 @@
#![cfg(feature = "clap")]

use clap::Parser;
use clap::{Args, Parser, ValueEnum};
use std::error::Error;
use std::io::{self, BufRead, Write};
use tzf_rs::DefaultFinder;

#[derive(Parser, Debug)]
#[command(name = "tzf")]
struct Cli {
/// longitude
#[command(flatten)]
params: Option<Params>,

/// Read multiple coordinates from stdin in given order
#[arg(long, conflicts_with("Params"))]
stdin_order: Option<StdinOrder>,
}

#[derive(Args, Debug)]
struct Params {
/// Longitude
#[arg(long, allow_negative_numbers(true), alias("lon"))]
lng: f64,

/// latitude
/// Latitude
#[arg(long, allow_negative_numbers(true))]
lat: f64,
}

pub fn main() {
#[derive(Clone, Debug, ValueEnum)]
enum StdinOrder {
#[value(alias("lon-lat"))]
LngLat,
#[value(alias("lat-lon"))]
LatLng,
}

fn is_delimiter(c: char) -> bool {
matches!(c, ' ' | '\t' | ',' | ';')
}

pub fn main() -> Result<(), Box<dyn Error>> {
let cli = Cli::parse();
let finder = DefaultFinder::new();
let tz_name = finder.get_tz_name(cli.lng, cli.lat);
println!("{tz_name:?}");
if let Some(params) = cli.params {
println!("{:?}", finder.get_tz_name(params.lng, params.lat));
} else if let Some(stdin_order) = cli.stdin_order {
let (mut stdin, mut stdout) = (io::stdin().lock(), io::stdout().lock());
let mut line = String::new();
while stdin.read_line(&mut line)? != 0 && line.ends_with("\n") {
let mut iter = line.chars().skip(1);
let i = 1 + iter.position(is_delimiter).expect("Missing delimiter");
let j = i
+ 1
+ iter
.position(|c| !is_delimiter(c))
.expect("Missing second coordinate");
let k = line.len() - if line.ends_with("\r\n") { 2 } else { 1 };
let (a, b) = (line[0..i].parse::<f64>()?, line[j..k].parse::<f64>()?);
let (lng, lat) = match stdin_order {
StdinOrder::LngLat => (a, b),
StdinOrder::LatLng => (b, a),
};
writeln!(stdout, "{:?}", finder.get_tz_name(lng, lat))?;
line.clear();
}
}
Ok(())
}

0 comments on commit 337a333

Please sign in to comment.