Musings of a dad with too much time on his hands and not enough to do. Wait. Reverse that.

Author: Brad (Page 16 of 57)

Dad. Technologist. Fan of English poet of John Lillison.

End of year gotcha in Java

Some of the data I work with sends dates in epoch or unix time. This works fine for software, but it is often helpful to convert those numbers to year, month, and day values for human consumption.

Consider the epoch time value: 1608552000.000 (the decimal places being for milliseconds)

Epoch Converter converts this value to: December 21, 2020 12:00:00 PM (GMT)

In Java, I might write code like this to convert the value:

import java.time.*;
import java.time.format.DateTimeFormatter;


class MyApplication{
    public static void main(String[] args){
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("YYYY-MM-dd");
        String uTime = "1608552000.000";
        Float fTime = Float.parseFloat(uTime);
        String sTime = LocalDateTime.ofInstant(Instant.ofEpochMilli((long) (fTime*1000)), ZoneOffset.ofHours(-5)).format(dtf);

        System.out.println(sTime);
    }
}

This code writes out the date: 2020-12-21

Job well done, right? Not so fast.

Consider this epoch value: 1609070400.000

Epoch Converter converts this value to: December 27, 2020 12:00:00 PM (GMT)

However, when I run this number through the code above, the output is: 2021-12-27

The year is wrong! What’s going on here? Well, it turns out the problem is with the date formatting pattern (line 7). In the code, I’m using “Y” (capital Y) to convert the year. The documentation defines this format as a “week-based-year”. December 27 was a Sunday. The first day of 2021 was the following Friday. My best guess is that, since part of that week changed to the year 2021, use of that particular format pattern must apply the year 2021 to all days in the week. Interesting.

Thankfully, if you want to get the actual year for that date, just use “y” (lowercase y). In code, that looks like this:

import java.time.*;
import java.time.format.DateTimeFormatter;


class MyApplication{
    public static void main(String[] args){
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        String uTime = "1609070400.000";
        Float fTime = Float.parseFloat(uTime);
        String sTime = LocalDateTime.ofInstant(Instant.ofEpochMilli((long) (fTime*1000)), ZoneOffset.ofHours(-5)).format(dtf);

        System.out.println(sTime);
    }
}

And now the output is as I expect: 2020-12-27

Scanning Family Scrapbooks

Old photos remounted on photo-safe paper

So far in my family genealogical endeavors, I’ve scanned over 3500 photos, including old ones on tin. Most of the photos I’ve scanned have been loose in shoe boxes and the like, but sometimes I run across an old scrapbook.

From my research, these scrapbooks usually are not the best way to preserve the photos they contain, so here are some steps I follow to better protect those images.

Take pictures of the original book

Before I start removing pictures from the original scrapbook, I’ll take pictures of it, cover-to-cover, page-by-page. For one, it’s nice to simply have a record of how the images were originally stored and ordered. Furthermore, once you start removing each photo, it may be helpful to have a reminder of what page each image came from and what other images surrounded it.

Take care removing the photos

Removing your photos might be tricky, depending on how they were mounted to the original scrapbook. I have found a standard business card a helpful tool in the effort where I slide it beneath an open edge and very carefully use it to pry the picture free. Check with the Internet, too, as you may find other helpful advice.

Scan and document each photo

In the past, I’ve discussed how I scan and document family slides. With photos, my approach is much the same:

File format? I’ve toyed with preserving my images as PNG or even TIF, but I predominantly stick to JPG, more for concern about disk space than anything else.

Naming convention? Long ago, I devised a naming convention that includes a person’s name along with a number in case I have multiple pictures of the same individual. For example, the file smith, john4.jpg would indicate the fourth picture I have of John Smith. This formula gets more complicated when there is more than one individual in a picture, which may make for a decent future blog post.

Documentation? For better or worse, I’m still quite “old school” when it comes to documenting my images, authoring something akin to a “read me” file in the folders where I store my files–I’ve talked a little about that approach in two previous posts. Long ago, I recall Leo Laporte recommending the book Digital Asset Management for Photographers for tips on photo storage and organization. That may be worth checking out as well as this old podcast episode.

Regardless, when documenting photos, I try my best to answer the Five Ws. If you’re lucky, your ancestor may have had the forethought to write some of those answers on the back of the photo (which is another reason to be able to gently remove the images from the original pages).

Remount the photos in a photo-safe scrapbook

Once you’ve scanned and documented your photos, you could pack them away in a photo-safe container. However, how about sharing them with the rest of your family in a photo-safe scrapbook?

I buy acid-free cardstock paper on which I mount the photos, slide them into clear, acid-free sleeves with holes for a three ring binder, and snap the pages into a nice, three ring binder. To mount the pictures to the paper, I use self-adhesive photo corner stickers.

Before I start mounting images to paper, I try to do a little planning. It may make sense to mount the pictures in the same order as they were in the original book. However, it might make more sense to group pictures by person–if you have several pictures of Aunt Sally, it might make sense to group all those together on a page or two labeled “Aunt Sally”. It might make sense to group pictures by event–if you have multiple pictures of a Christmas in 1955, it might make sense to keep them together on a page called “Christmas 1955”.

While the self-adhesive photo corners do make it much easier to remove your pictures and look on the back for any notes, I try to add labels of any important information below each photo, so that it shouldn’t be necessary to pull out a given picture just to see what may be written on the back. You can check out the picture I took of one of my scrapbook pages (above) for details. One change I’ve made since I put that page together, though, is that I now use an easier-to-read font like Arial for my labels.

Include your pictures of the original scrapbook

Remember how I recommended taking a picture of the original scrapbook? I like to include copies of those pictures in a page or two of the new version, especially if the original had a neat look to it. You may not want to include every picture: maybe just the covers and an example page.

Include a cover page

Finally, it may be helpful to include a printed cover page in the new scrapbook describing how you migrated the photos from the original scrapbook to the new, safer version. Include the date(s) you did the work and your own contact information, so family knows who did this great work and who has electronic copies of the images.

Good idea for those loose pictures, too

While it might not be feasible to make scrapbooks for all your loose photos, your family might be well served by mounting many of your loose pictures in photo-safe scrapbooks, too.

So, how are you dealing with your old scrapbooks and loose photos? I’d love you hear your thoughts and suggestions!

Music to Drive By: Python Edition

If only Wayne and Garth had a thumb drive of music to listen to

In the past, I’ve written about using PowerShell to help build a thumb drive of music to listen to in the car. Recently, I took a crack at converting that work to Python with the help of the pymediainfo package. Here’s what I did:

Load the requisite packages

import os
import pandas as pd
import json
import shutil

Build your music inventory

The to_data function of pymediainfo makes it very easy to gather all the important properties of your music files. Optionally, I wrote code to save that inventory out to a json file for later analysis, but you don’t have to do that to build your thumb drive. I hard coded the path to my music folder (D:\music_backup) and my code does assume that you only want to process mp3 files (line 4).

music_col = []
for dirpath, dirs, files in os.walk("D:\\music_backup"):
    for filename in files:
        if filename.lower().endswith('mp3'):
            fname = os.path.join(dirpath,filename)
            mi = MediaInfo.parse(fname)
            music_col.append([t for t in mi.tracks if t.track_type == 'General'][0].to_data())

# save collection to file if needed
with open('music_col.json', 'w') as f:
    json.dump(music_col, f) 

Build a pandas dataframe

Yes, pandas is my go-to “hammer” to solve most of my coding problems. I use the fillna function to replace any null values with empty strings–makes filtering easier later on.

df_music = pd.DataFrame(music_col)
df_music = df_music.fillna('')

Filter on just the music I want to listen to in the car

As I’ve said before, I have a lot of music in my library but technical limits with my car stereo. So, I have to make certain decisions on what music to copy. Dataframe filtering makes that fast and easy. To make things interesting, I’m leveraging the pandas sample function to randomly sort my music. Here’s the code I came up with:

genres_to_include = ["Pop", "Rock", "Hard Rock & Metal"]

album_artists_to_exclude = ["ABBA", "Disney", "Vanilla Ice"]
albums_to_exclude = ["Frozen [Original Motion Picture Soundtrack]", "High School Musical 2 [Original Soundtrack]", "The Smurfs 2- Music from and Inspired By"]
# excluded any "songs" that might actually be talking of some sort
bad_titles = 'interview|speech'

df_usb = df_music[(df_music.genre.isin(genres_to_include)) & ~(df_music.performer.isin(album_artists_to_exclude)) & 
                  ~(df_music.album.isin(albums_to_exclude)) & ~(df_music.title.str.contains(bad_titles, case=False)) & 
                  (df_music.duration>30000)].sample(frac=1)

Don’t forget about the size constraints of the thumb drive

I’m using a 16Gb thumb drive and I have well over 50Gb of music, so I need to make sure I only copy over enough files to fill up the drive and nothing more. The pandas cumsum function will help me easily figure that out:

df_usb['file_size_cumsum'] = df_usb.file_size.cumsum()

Finally, write to the thumb drive

Now, I’m ready to write my randomized music, filtered just how I want, to my thumb drive:

# set a max bytes of about 15.7 Gb
max_bytes = 15700000000
usb_drive = 'E:\\.'

for f in df_usb[df_usb.file_size_cumsum<max_bytes].complete_name.tolist():
    shutil.copy(f, usb_drive)

« Older posts Newer posts »

© 2024 DadOverflow.com

Theme by Anders NorenUp ↑