Telephone numbers: not as easy as they look

In ONEIS, we have to handle lots of different types of data. One of the more difficult is telephone numbers — they may look simple, but if you want to manage them well there’s a lot you need to get right.

When I was researching how to handle telephone numbers, I couldn’t find anything which described the problems and potential solutions. So here are some notes on what I found and how we handle phone numbers in ONEIS. Hopefully it’ll be of use to anyone else trying to solve these problems, and of interest to those involved in data and information management.

Not just a number

Telephone numbers are made up of several parts. I’ll use our phone number as an example.

Telephone number

  • Subscriber number, which identifies who to call
  • Area code, which identifies where the number is geographically based
  • Trunk code, used to dial between area codes (not used for international dialing)
  • International dialing code, used to dial between countries, with the + replaced by an access code

Every country has different rules, with varying access codes for international dialing. Trunk codes, used for national dialing, can be 0, 1, or sometimes no trunk code at all. Area codes are many different lengths, and may not be the same within a country — in the UK we use shorter codes for larger areas, but in the US multiple unrelated area codes are used for a single large area.

And finally, the preferred way of writing a number varies. In France, numbers are written 01 23 45 67 89, but in the US 1-234-567-8901.

Not as simple as it looks

There’s a lot of potential for getting things wrong, especially when you’re entering phone numbers for an unfamiliar country. We could just use a simple text field and let our users enter anything. This is adequate, until you want to do something more than just displaying the number.

For example, our clients keep their contact directories on ONEIS, and then sync them to their phones. The phone numbers are from all over the world, and must be synced in the full international format so that they can be dialed successfully from any country. If we just copied a phone number to the phone, the chances of it working are quite small as it probably won’t specify the country.

We’re also rather picky on everything looking good and consistent. There are lots of ways you can write a phone number, so we want to display them properly according to the local standards for the country. Finally, and most usefully, we want to show each user the number they would actually dial on the phone on their desk.

Not even consistent

Once a system understands how phone numbers are structured, it then has to deal with lots of other complications:

  • Some countries share international dialing codes, and use area codes to distinguish between them.
  • Countries which aren’t on the international standard ISO 3166-1 list have dialing codes
  • Some of the very small countries with ISO codes don’t have international dialing codes
  • The Vatican has an ISO code and an international dialing code, but actually uses an Italian area code
  • Everything changes over time, for example, the Soviet Union no longer exists and some of the new nations have since gained their own country code
  • Some companies use internal extensions, which you want to record, but are never dialed on the public telephone system

As a result, if a number is to be completely unambiguous and future proof, the country must be stored along with the phone number. Then, when they’re used, the system must know quite a bit about the world’s numbering plan.

Our solution

Storing phone numbers

We store phone numbers as

  • ISO country code, or if the country doesn’t have one, it’s international dialing code
  • The telephone number, as the user entered it, however it’s formatted and may or may not include the trunk code
  • An optional extension number

We use the ISO country code to identify the country, not the dialing code, because countries share codes. However, for countries with dialing codes but not ISO codes, we have to be pragmatic and use the dialing code instead.

Even though we may change the format when it’s displayed, the phone number we store ‘behind the scenes’ is exactly as it was entered. It’s important not to throw away data so we can adapt to changes in the numbering system, and you never know when it might be useful later. This also has the advantage that when you edit a telephone number it’s always exactly as you last left it, regardless of how it’s displayed elsewhere.

Importing phone numbers

When we import data, it’s rarely perfect. While the data is often perfectly fine for people to use and interpret, computers require more precision. The system has to guess which country it’s in, using roughly the same rules as you would. We make pretty good guesses using hints from how they’re formatted, country codes, international prefixes, and the country the users entered them in.

For example, we’ve seen number formats like 020 7047 1111, 0044 20 7047 1111, +44 20 7047 1111, 20 7047 1111, which are all the same UK number. Or numbers like 1-123-456-7894, which is a US number, but could be interpreted as the UK number 01123 4567894 if you didn’t guess the country. I think we do a pretty good job, and so far we’ve handled most of the data with minimal manual correction.


We want to be very helpful about how we display phone numbers. To enable this, we store the ‘home country’ for each user, so we know where they are and how they expect their phone numbers to be formatted. So, if a user is based in the UK, they see our phone number as

020 7047 1111

but if they are in any other country, they see

(United Kingdom) +44 20 7047 1111

The aim is to always present numbers which will work when dialed, display the number in a consistent and familiar form, and be helpful about showing country names.

To get this level of quality,

  • Where we have information about how numbers are formatted for that country, we reformat them so they’re all consistent
  • The system removes or adds the trunk code as necessary, depending on whether the number is shown in local or international format
  • Extensions are handled consistently, displayed after the number
  • If your home country is a North American NANP country, you just see the trunk code and not the +1 dialing code for other NANP countries (you can dial foreign NANP numbers from within any NANP country without an international access code)

To achieve this, we have a large and detailed table of information about each country:

  • Name (for example, ‘United Kingdom’)
  • ISO code (‘GB’)
  • Dialing code (‘44’)
  • How to dial an international number (‘00’ access code)
  • The trunk code, if used (‘0’)
  • If it’s a country where we have lots of users, we also know how the numbers are formatted. In the UK, it’s quite complicated, as the area codes vary in size.

ONEIS also knows about the North American Numbering Plan, NANP, which covers the US, Canada and some Caribbean countries under the +1 international dialing code. The area codes determine which country the phone numbers are in, so there’s a list of all the non-US codes to enable us to show the countries correctly.

Of course, this information may change over time. Because we keep the number as it was entered and do any corrections when it’s displayed, we can very easily correct any issues later. Given the amount of complex rules involved in telephone numbers, it’s important to design a system which can adapt and be corrected.

User interface

As well as thinking about how the numbers are stored and displayed, we’ve done a lot of work to make sure they’re easy to enter into the system. Here’s our editor, split into country and dialing code, the number itself, and the extension:

Entering the country from a long drop down list is quite fiddly and time consuming, so we have minimised the times you’ll need to use it. The default country is your home country, so most times you won’t need to change it.

But for the times when you do, our trick is to put a bit of intelligence into the editor. When you’re entering an international number, you’re often copying it from something with the code. So, if you type + followed by a valid country code, the country is selected in the drop down list automatically. When you know the country but not the code, you can use the drop down list to find it.

Because we handle trunk codes automatically, you can either enter it or not, and it’ll be handled correctly when it’s displayed and used.

Finally, it understands NANP codes. If you’re entering a number for any +1 country and the area code doesn’t match that country, the editor will automatically correct it for you.

This all means that you can just type in a number, and everything will just work. High quality data for minimal effort.


Searching for phone numbers is tricky. You can’t just use a standard keyword search, because of the wide variety of ways in which they’re formatted. Instead, you have to store them separately, with country and number without any spaces or punctuation, and use a right anchored search on as much of the number as you’re given. Extension numbers are ignored completely, because they’ll probably be more confusing than useful.

Caller ID can present the number in many different ways, depending on your phone company, so again we need to be able to understand the number well enough to reduce it to something which can be searched. This allows us to show the information you hold on the caller when the phone rings.

The beauty is in the detail

This may seem like a lot of effort to handle telephone numbers, but a system like ONEIS is made up of lots of little details. If the system is to feel right, all of the details have to be spot on.

We believe systems should make it easy to do the right thing, where the effortless approach is the correct approach. Perhaps our users won’t notice the little things, but the experience of using it will be satisfying and productive.

Subscribe Ben’s technical blog