Skip to content

Commit

Permalink
Made the app generic
Browse files Browse the repository at this point in the history
  • Loading branch information
isurfer21 committed Dec 2, 2019
1 parent 943d8a8 commit 96843a1
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 56 deletions.
31 changes: 14 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,21 @@
A tool to shorten (encode) the date and expand (decode) shortened date back to original date

## Introduction
I have developed a new way to encode/decode dates within 3 characters by using base-36 format.
I have developed a new way to encode/decode dates within 3 or 4 characters by using base-99 format.

#### What is a base 36 format?
#### What is a base 99 format?

> Base 36 or hexatridecimal is a positional numeral system using 36 as the radix. The choice of 36 is convenient in that the digits can be represented using the Arabic numerals 0-9 and the Latin letters A-Z.
In simple language, base-36 format refers to series of 0-9 followed by A-Z characters, i.e., 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ; where each character refers to the position index in series.
In simple language, base-99 format refers to series of 0-9 followed by small & capital A-Z characters and variations of vowel characters, i.e., 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZàèìòùÀÈÌÒÙáéíóúÁÉÍÓÚâêîôûÂÊÔÛÎäëïöüÄËÏ; where each character refers to the position index in series.

e.g., `12 → C, 19 → J, 34 → Y`

Now here is a way to use the same logic for date, so to do that let us take a date and encode it as

`25-Oct-2019 → 25-10-2019 → 25.10.19 → P.A.J → paj`
`15-8-2019 -> 15.8.2019 -> f.8.kj -> f8kj`

Similarly, decode it back as

`paj → P.A.J → 25.10.19 → 2019-10-25 → 25-Oct-2019`

Note, here `P.A.J` is converted to lowercase as paj to make it more compact.
`f8kj -> f.8.kj -> 15.8.2019 -> 15-8-2019`

## Usage
Open the application in terminal & run the required commands as shown below
Expand All @@ -30,13 +26,13 @@ Few sample usages are given below

```
$ ds -t
tbj
$ ds -t -e
29-11-2019 -> 29.11.19 -> T.B.J -> tbj
$ ds -c tbj -e
tbj -> T.B.J -> 29.11.19 -> 29-11-2019
$ ds -d 28/11/2019 -e
28-11-2019 -> 28.11.19 -> S.B.J -> sbj
2ckj
$ ds -t -s
2-12-2019 -> 2.12.2019 -> 2.c.kj -> 2ckj
$ ds -d 2ckj -s
2ckj -> 2.c.kj -> 2.12.2019 -> 2-12-2019
$ ds -e 2/12/2019 -s
2-12-2019 -> 2.12.2019 -> 2.c.kj -> 2ckj
```

### Help
Expand Down Expand Up @@ -74,7 +70,7 @@ See the currently available version
```
$ ds -v
Date Shortener
Version 1.0.0
Version 0.2.0
Licensed under MIT License
```

Expand All @@ -96,5 +92,6 @@ $ cd date-shortener
$ cargo build --release
$ ./target/release/ds -h
```

## References
- [Encode or decode date in 3 characters](http://akzcool.blogspot.com/2019/10/encode-or-decode-in-3-characters.html)
57 changes: 57 additions & 0 deletions src/endec.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
const SYMBOLS: &str = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZàèìòùÀÈÌÒÙáéíóúÁÉÍÓÚâêîôûÂÊÔÛÎäëïöüÄËÏ";

pub fn encode(day:u32, month:u32, year:i32, steps:bool) -> String {
let symbols: Vec<char> = SYMBOLS.chars().collect();
let symbols_count = SYMBOLS.len();
let enc_day = symbols[(day % symbols_count as u32) as usize];
let enc_month = symbols[(month % symbols_count as u32) as usize];
let enc_year: String;
if year > 100 {
let long_year: i32 = year;
let century: i32 = long_year / 100;
let short_year: i32 = long_year % 100;
let enc_century = symbols[(century % symbols_count as i32) as usize];
let enc_short_year = symbols[(short_year % symbols_count as i32) as usize];
enc_year = format!("{}{}", enc_century, enc_short_year);
} else {
enc_year = symbols[(year % symbols_count as i32) as usize].to_string();
}
let dmy = format!("{}{}{}", enc_day, enc_month, enc_year);
let dmy_with_steps = format!("{}-{}-{} -> {}.{}.{} -> {}.{}.{} -> {}", day, month, year, day, month, year, enc_day, enc_month, enc_year, dmy);
return if steps { dmy_with_steps } else { dmy };
}

pub fn decode(encoded_date:String, steps: bool) -> String {
let enc_date_sym: Vec<char> = encoded_date.chars().collect();
let enc_day = enc_date_sym[0];
let enc_month = enc_date_sym[1];
let enc_year = &encoded_date[2..encoded_date.len()];
let dec_day = SYMBOLS.find(enc_day).unwrap();
let dec_month = SYMBOLS.find(enc_month).unwrap();
let enc_date_len = enc_date_sym.len();
let mut dec_year = SYMBOLS.find(enc_date_sym[enc_date_len-1]).unwrap();
if enc_date_len > 3 {
let dec_century = SYMBOLS.find(enc_date_sym[enc_date_len-2]).unwrap();
dec_year = ((dec_century as i32 * 100) + dec_year as i32) as usize;
}
let dmy = format!("{}-{}-{}", dec_day, dec_month, dec_year);
let dmy_with_steps = format!("{} -> {}.{}.{} -> {}.{}.{} -> {}", encoded_date, enc_day, enc_month, enc_year, dec_day, dec_month, dec_year, dmy);
return if steps { dmy_with_steps } else { dmy };
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn encode_works() {
assert_eq!(encode(31, 12, 2035, false), "vckz");
assert_eq!(encode(31, 12, 35, false), "vcz");
}

#[test]
fn decode_works() {
assert_eq!(decode("vckz".to_string(), false), "31-12-2035");
assert_eq!(decode("vcz".to_string(), false), "31-12-35");
}
}
78 changes: 39 additions & 39 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,43 @@ use getopts::Options;
use chrono::prelude::*;
use std::env;

const BASE36_CHARSET: &str = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const VERSION: &str = "0.1.0";
mod endec;

const VERSION: &str = "0.2.0";

const L10N_APPVER: &str = "
Date Shortener
Version [VER]
Licensed under MIT License
";

const L10N_APPINFO: &str = "
Date Shortener
It is a tool to shorten (encode) the date and expand (decode) shortened date back to original date.
";

const L10N_APPCLIEX: &str = "
Examples:
$ ds -v
$ ds -t
$ ds -t -s
$ ds -e 15/08/19
$ ds -e 15/08/2019 -s
$ ds -d f8j
$ ds -d f8kj -s
";

fn main() {
let args: Vec<String> = env::args().collect();
let program = args[0].clone();

let mut opts = Options::new();

opts.optopt("d", "date", "encode the provided date", "DD-MM-YYYY");
opts.optopt("c", "code", "decode the provided code", "DMY");
opts.optopt("e", "encode", "encode the provided date", "DD-MM-YYYY");
opts.optopt("d", "decode", "decode the provided code", "DMY");

opts.optflag("t", "today", "encode today's date");
opts.optflag("e", "explain", "explain with steps");
opts.optflag("s", "steps", "show with steps");
opts.optflag("h", "help", "display the help menu");
opts.optflag("v", "version", "display the application version");

Expand All @@ -33,27 +56,27 @@ fn main() {
}

if matches.opt_present("v") {
println!("Date Shortener \nVersion {} \nLicensed under MIT License", VERSION);
println!("{}", L10N_APPVER.replace("[VER]", VERSION));
return;
}

let mut explain_flag = false;
if matches.opt_present("e") {
explain_flag = true;
let mut steps_flag = false;
if matches.opt_present("s") {
steps_flag = true;
}

if matches.opt_present("t") {
let local: DateTime<Local> = Local::now();
let dmy = to_date36(local.day(), local.month(), local.year(), explain_flag);
let dmy = endec::encode(local.day(), local.month(), local.year(), steps_flag);
println!("{}", dmy);
}

let date = matches.opt_str("d");
let date = matches.opt_str("e");
match date {
Some(date) => {
let tmp: Vec<&str> = date.split([',', '.', '-', '/'].as_ref()).collect();
if tmp.len() == 3 {
let dmy = to_date36(tmp[0].parse().unwrap(), tmp[1].parse().unwrap(), tmp[2].parse().unwrap(), explain_flag);
let dmy = endec::encode(tmp[0].parse().unwrap(), tmp[1].parse().unwrap(), tmp[2].parse().unwrap(), steps_flag);
println!("{}", dmy);
} else {
println!("Invalid date: {:?}", date);
Expand All @@ -62,10 +85,10 @@ fn main() {
None => do_nothing(),
}

let code = matches.opt_str("c");
let code = matches.opt_str("d");
match code {
Some(code) => {
let dmy = to_date_str(code, explain_flag);
let dmy = endec::decode(code, steps_flag);
println!("{}", dmy);
},
None => do_nothing(),
Expand All @@ -75,31 +98,8 @@ fn main() {
fn do_nothing() {}

fn print_usage(program: &str, opts: Options) {
println!("Date Shortener is a tool to shorten (encode) the date and expand (decode) shortened date back to original date. \n");
println!("{}", L10N_APPINFO);
let brief = format!("Usage: {} [flag] [options]", program);
print!("{}", opts.usage(&brief));
println!("\nExamples: \n $ ds -v \n $ ds -t \n $ ds -t -e \n $ ds -d 15/08/2019 \n $ ds -d 15/08/2019 -e \n $ ds -c f8j \n $ ds -c f8j -e \n");
}

fn to_date36(day:u32, month:u32, long_year:i32, explain:bool) -> String {
let symbols: Vec<char> = BASE36_CHARSET.chars().collect();
let short_year = long_year % 100;
let d36 = symbols[(day % 36) as usize];
let m36 = symbols[(month % 36) as usize];
let y36 = symbols[(short_year % 36) as usize];
let dmy = format!("{}{}{}", d36, m36, y36).to_ascii_lowercase();
let dmy_explained = format!("{}-{}-{} -> {}.{}.{} -> {}.{}.{} -> {}", day, month, long_year, day, month, short_year, d36, m36, y36, dmy);
return if explain { dmy_explained } else { dmy };
}

fn to_date_str(date36:String, explain: bool) -> String {
let date36_uc = date36.to_ascii_uppercase();
let date_sym: Vec<char> = date36_uc.chars().collect();
let day = BASE36_CHARSET.find(date_sym[0]).unwrap();
let month = BASE36_CHARSET.find(date_sym[1]).unwrap();
let short_year = BASE36_CHARSET.find(date_sym[2]).unwrap();
let long_year = short_year as i32 + 2000;
let dmy = format!("{}-{}-{}", day, month, long_year);
let dmy_explained = format!("{} -> {}.{}.{} -> {}.{}.{} -> {}", date36, date_sym[0], date_sym[1], date_sym[2], day, month, short_year, dmy);
return if explain { dmy_explained } else { dmy };
println!("{}", L10N_APPCLIEX);
}

0 comments on commit 96843a1

Please sign in to comment.