Picking a random date between two dates

Picking a random date between two dates

Many years ago I created the Fake Name Generator, a website that lets you create fake names, addresses, birth dates, and other profile information. I’ve had issues with the birth date component ever since I wrote the dang thing, including a huge bug I fixed a few years ago.

Well today I was informed of another bug. A while back I added the ability for visitors to select an age range for their generated identities. The code that handled this was atrocious: it would figure out the birth year range by subtracting the selected min/max ages from the current year, then pick a random year within that range. It would then pick a random number 1 to 12 to represent the month, a random number 1 to 31 to represent the day of the month, then it would use checkdate() to see if the date is valid (for example, 2/31/1990 would be invalid). If it is invalid, it would try again. Most of the possible generated dates are valid so it only occasional has to try again.

Aside from being ugly, the big problem with this code is that it doesn’t always generate birth dates within the selected age range. Say you want to generate a birth date that would make someone at least 19 years old and no older than 19 years old (i.e., exactly 19 years old). In January most of the generated birth dates will make an 18 year old, in June you’ll have about a 50/50 split of 18 and 19 year olds, and in December most will be 19 year olds. This is because my code was only dealing with the birth year, and wasn’t taking into account the birth day or month in relation to the current date. Not very noticeable if your age range is something like 1 to 100 years old, but very noticeable if it is January 10th and you want a birth date for a 19 year old. Like I said, horrible code.

So here is my latest try. This function takes a minimum and maximum age as parameters, and spits out an array with the birth date and age:

function dateTime($minAge = 19, $maxAge = 85)
{
    // Sanity check
    if(!is_numeric($minAge)) $minAge = 19;
    if(!is_numeric($maxAge)) $maxAge = 85;
    if($minAge > $maxAge) $minAge = $maxAge;

    $tz = new DateTimeZone('US/Eastern');

    $minDate = new DateTime('now', $tz);
    $minDate->modify("-$maxAge years -1 year +1 day");
    $maxDate = new DateTime('now', $tz);
    $maxDate->modify("-$minAge years");

    $minEpoch = $minDate->format('U');
    $maxEpoch = $maxDate->format('U');

    $birthday = new DateTime('@'.mt_rand($minEpoch, $maxEpoch), $tz);
    $today = new DateTime('now', $tz);

    $date = array(
        'year'      => $birthday->format('Y'),
        'month'     => $birthday->format('n'),
        'month-name'=> $birthday->format('F'),
        'day'       => $birthday->format('j'),
        'formatted' => $birthday->format('n/j/Y'),
        'age'       => $today->diff($birthday)->y,
    );

    return $date;
}

The code is a bit long, but is actually pretty straightforward:

First we do a little sanity check. I want my code to return valid data even if someone manages to pass in a bad value, so I check to make sure the min and max ages are numeric and that the min age isn’t larger than the max age. This could be improved, but I think it is good enough for my needs.

Next we create a DateTimeZone object. My server’s time is set to US Eastern, so I want all my dates to use this time zone. This object will get passed into the constructor for DateTime later in the code.

In the next block of code I create two DateTime objects with today’s date. I use the modify method to subtract an appropriate amount of time from each object so I get the minimum and maximum birth date that someone could have and still fall within the desired age range. DateTime makes this easy by allowing things like +1 day. It doesn’t care about plurals, so you can use day and days, year and years interchangeably and inappropriately.

This next bit was a stroke of genius (which I later discovered is what some experts online would consider “the obvious way”). I convert the minimum and maximum dates into Unix timestamps, which are just integers. So if we are generating an identity for someone between 20 and 50 years old, the minimum date would be something like -219961293 and the maximum would be 758259507.

Now that our dates are just integers, picking a random date between the two is easy. I create a new DateTime object with the date set to a random Unix timestamp between the minimum and maximum Unix timestamps I came up with in the previous step. I then create another DateTime object, $today, to use later to come up with the identity’s age.

I use an array to hold each bit of the birth date, a formatted version of the birth date, and the age. To get the parts of the birth date I just call the format method on my $birthday DateTime object. To get the age I use the diff method on my $today DateTime object to find the number of full years between the $birthday object and the $today object.

If all you want is to pick a random date between two dates, then this is obviously more than you need. You could probably get away with this, if you were sure that the input dates were valid:

function randomDate($startDate = 'now', $endDate = 'now')
{
    $minDate = new DateTime($startDate);
    $maxDate = new DateTime($endDate);

    $minEpoch = $minDate->format('U');
    $maxEpoch = $maxDate->format('U');

    $randomDate = new DateTime('@'.mt_rand($minEpoch, $maxEpoch));
    $today = new DateTime('now');

    $date = array(
        'year'      => $randomDate->format('Y'),
        'month'     => $randomDate->format('n'),
        'month-name'=> $randomDate->format('F'),
        'day'       => $randomDate->format('j'),
        'formatted' => $randomDate->format('n/j/Y'),
        'age'       => $today->diff($randomDate)->y,
    );

    return $date;
}

DateTime can figure out most dates, so you could do something like randomDate(‘March 1, 1980’, ‘5/20/1999’). If you don’t pass any dates in then it will use today’s date.

I could probably re-use some of those DateTime objects, but I don’t think having a few of them matters enough to obfuscate the code. I could also just return the $birthday object rather than building an array to return, but my existing code expects an array.

I’m open to critiques and suggestions for improvements. I’m thick skinned so feel free to completely bash my code if you’d like. Or if you are having a problem with the code, please let me know and I’d be happy to try to help you out!

Read More

Enabling mouse support in Vim

Enabling mouse support in Vim
Hopefully you are using newer equipment than this...

Hopefully you are using newer equipment than this…

If you’ve ever logged into a server using an ssh client (like PuTTY), then you’ve probably used Vim. This infinitely customizable text editor typically runs within a keyboard-only shell, and thus only lets you use the keyboard (unless you are running something like gVim). You use the arrow keys to move the cursor around and a slew of keyboard shortcuts to insert, move, delete, or otherwise manipulate the text.

If you are a Linux user I just told you a bunch of stuff you already know. But did you know that Vim has mouse support? You just have to turn it on. Open Vim and enter this command:

:set mouse=a

You’ll now have mouse support until you exit Vim and load it up again. To make the change permanent, edit your .vimrc file (typically at ~/.vimrc) and add set mouse=a to the end of the file.

So how do you use the mouse in Vim? What benefits will you get? There are a few things you need to know:

  1. Copying text: You may be in the habit of highlighting text and having it put on your system’s clipboard. This won’t work anymore. When you click and drag to highlight text, you’ll be put into Visual mode, an amazingly powerful part of Vim that many people never use. I highly recommend learning more about Visual mode, but if you want the original behavior you can hold shift while selecting text.
  2. Placing the cursor: Instead of having to use the arrow keys to move your cursor, you can now just click wherever you want it to be. Huge time saver.
  3. Scrolling: Yup, you can scroll with the mouse wheel now. No more hitting page down a hundred times in a giant file. Just scroll that wheel to get to wherever you want in your file.

After a few days of reaping the many benefits of Douglas Engelbart’s wonderful little invention, you may be asking yourself: Why isn’t mouse support turned on by default?! I’m not really sure. I did a bit of searching but couldn’t find a definitive answer. If you figure it out, please let me know!

Read More

We’re making a video game

I’m the assistant scoutmaster in my ward’s Boy Scout troop. I’m not very good at it. I don’t particularly enjoy camping without my family, and I’m not very good at tying any kind of knot other than a square knot or a one-handed bowline. It has been a real struggle to find ways to be useful to my troop and the boys that are in it.

While I was driving some of them home after a troop meeting a few days ago, one of them asked the others what they wanted to be when they grew up. One of them said they wanted to make video games. Being a programmer, I know that is easier said than done.

I started thinking about it though. Is it really that hard? What is required to make a video game? Well, nowadays you generally pick a platform, work within a framework, come up with a story line and some graphics, then code the game. I’m no good with graphics and story lines, but I can do the other bits. I browsed DreamSpark and found some free development tools and decided I wanted to offer to teach the boys in my troop how to make a video game.

Tonight we were having a movie night but a few people were running late so most of us were just hanging out, so I took the opportunity to bring up my idea to create a video game. They loved it! We spent 30-45 minutes coming up with a plot, weapon ideas, how the player should move through the game, power ups, customization options (like character clothes), and assigned a few people to draw some artwork.

We are going to try meeting once a week with whoever is interested so we can work on the game. The initial goal is to get a basic single level finished. We are going to use Microsoft XNA Game Studio with the hopes of having our game available for both Windows and Xbox 360.

I feel this is a bit ambitious, but I’m really excited about it! XNA uses C#, which I’m somewhat familiar with, and has a bunch of good books available for it. One of the boys has had a basic programming class before, so that should help some. And all of them play way more video games than they should, so they should know what makes a game fun or boring.

I’ll do another post once we get some artwork and a title, hopefully in just a few days.

Read More

Creating a temporary email service

A long time ago I created a temporary email service (Fake Mail Generator) using an open source script. Shortly after, my shared hosting provider shut me down because it was using too many resources.

This weekend I finally got it up and running again, and I’d like to share the basics of how I did it. You’ll still have to figure some parts out on your own, but at least you’ll have a basic idea of what to do.

First, I needed somewhere to host my email service. I know from experience that some hosts aren’t too pleased with this type of service, so I didn’t want to put it on my main dedicated server. Instead, I found a great VPS (virtual private server) at AlienVPS for only $6.75/month. I get shell access, plenty of disk space and bandwidth, and 512MB of RAM.

There is always the risk that they’ll decide to cancel my service without warning, so I store all my code (including config files and database schema) in a git repository. I think it’d take me less than an hour to get completely up and running on a new host if I had to.

Second, I needed a domain name to use for the email service. These need to be changed every now and then, so I couldn’t use the fakemailgenerator.com domain. I’ve had problems with domain registrars in the past getting upset over my usage of the domain, too, so I went to a registrar I’ve never used before. I chose Gandi.net because they have a history of standing up for the rights of their users, and I registered teleworm.com.

Last, I needed a way to process incoming email. This was the part that took a little effort to figure out because I lost the original instructions to the open source script I was using.

The first step was to install postfix. I’m using CentOS so this was as easy as yum install postfix.

Next, some basic configuration. In /etc/aliases I had to add a mailbox that sends the mail to a PHP script. For me this looks like:

fmg: "| php -q /www/fakemailgenerator/mail-handler.php"

This tells postfix to send all mail addressed to fmg to a PHP script called mail-handler.php. Once I made this change to aliases, I had to run newaliases (no parameters required).

Next I needed to setup a catch-all for my domain. This is done in /etc/postfix/virtual:

@teleworm.com fmg

This tells postfix to accept mail for anything@teleworm.com, and send it to the fmg account I configured in /etc/aliases.

If your /etc/postfix/main.cf doesn’t already have it set, it needs the following lines:

alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
smtpd_banner = mail.teleworm.com ESMTP $mail_name
myhostname = mail.teleworm.com
virtual_alias_domains = teleworm.com
virtual_alias_maps = hash:/etc/postfix/virtual

Last, run the following to enable your new configuration (assuming postfix is already running):

postmap /etc/postfix/virtual
postfix reload

Yay! We now have mail addressed to any address at teleworm.com going to a PHP script. Lucky for me, I already have a basic handler. Unluckily for you, you don’t.

To point you in the right direction, this is how you get the content of the email into a variable called $email:

$fd = fopen("php://stdin", "r");
$email = "";
while (!feof($fd)&&!(strlen($email)>=5000)) {
 $email .= fread($fd, 1024);
}
fclose($fd);

Once you have the email in a variable, you can parse out the to, from, and the body. You can save it to a database or save to a file or do whatever you want. You can check if the to address has been activated, and if not, you can cause a “user not found” message to be sent by doing something like die(‘550 User not found.’). It is entirely up to you.

Anyways, it was fun to get going again, and I have a lot of ideas on how to improve the code I already have.

Read More

Yo IDE is so old that when asked for its version number it gives a Roman numeral

I’ve had the pleasure poke-my-own-eyes-out-with-a-stick torture of doing a lot of VB6 programming at work lately. The language is pretty primitive compared to newer languages, but it isn’t too bad.

The thing that has been really getting on my nerves is the inability to scroll the page with my mouse’s scroll wheel. VB6 is literally so old that the IDE doesn’t know what to do when you scroll your mouse wheel. Considering the scroll wheel is a 15 year old technology, it is likely that some of my younger readers have never even used a mouse without a scroll wheel.

Well, thanks to Microsoft’s commitment to supporting their antiquated software, there is a solution! Microsoft provides an add-in DLL that makes the VB6 IDE smart enough to know what to do with the scroll wheel. Installation takes about 2 minutes and so far so good.

Get the DLL direct from Microsoft here.

Read More